Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Resolver/ResolveAtLocation.cs @ 17401

Last change on this file since 17401 was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 6.0 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Threading;
21using ICSharpCode.NRefactory.CSharp.TypeSystem;
22using ICSharpCode.NRefactory.Semantics;
23using ICSharpCode.NRefactory.TypeSystem;
24
25namespace ICSharpCode.NRefactory.CSharp.Resolver
26{
27  /// <summary>
28  /// Helper class that resolves the node at a specified location.
29  /// Can be used for implementing tool tips.
30  /// </summary>
31  public static class ResolveAtLocation
32  {
33    public static ResolveResult Resolve (ICompilation compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location,
34                                        CancellationToken cancellationToken = default(CancellationToken))
35    {
36      return Resolve (new Lazy<ICompilation>(() => compilation), unresolvedFile, syntaxTree, location, cancellationToken);
37    }
38    public static ResolveResult Resolve(Lazy<ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location,
39                                        CancellationToken cancellationToken = default(CancellationToken))
40    {
41      AstNode node;
42      return Resolve(compilation, unresolvedFile, syntaxTree, location, out node, cancellationToken);
43    }
44   
45    public static ResolveResult Resolve (ICompilation compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node,
46                                        CancellationToken cancellationToken = default(CancellationToken))
47    {
48      return Resolve (new Lazy<ICompilation>(() => compilation), unresolvedFile, syntaxTree, location, out node, cancellationToken);
49    }
50    public static ResolveResult Resolve(Lazy<ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node,
51                                        CancellationToken cancellationToken = default(CancellationToken))
52    {
53      node = syntaxTree.GetNodeAt(location);
54      if (node == null || node is ArrayInitializerExpression)
55        return null;
56      if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole) {
57        var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile);
58        return r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken);
59      }
60      if (CSharpAstResolver.IsUnresolvableNode(node)) {
61        if (node is Identifier) {
62          node = node.Parent;
63        } else if (node.NodeType == NodeType.Token) {
64          if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer || node.Role == IndexerDeclaration.ThisKeywordRole) {
65            // There's no other place where one could hover to see the indexer's tooltip,
66            // so we need to resolve it when hovering over the '[' or ']'.
67            // For constructor initializer, the same applies to the 'base'/'this' token.
68            node = node.Parent;
69          } else if (node.Parent is BinaryOperatorExpression || node.Parent is UnaryOperatorExpression) {
70            // Resolve user-defined operator
71            node = node.Parent;
72          } else {
73            return null;
74          }
75        } else {
76          // don't resolve arbitrary nodes - we don't want to show tooltips for everything
77          return null;
78        }
79      } else {
80        // It's a resolvable node.
81        // However, we usually don't want to show the tooltip everywhere
82        // For example, hovering with the mouse over an empty line between two methods causes
83        // node==TypeDeclaration, but we don't want to show any tooltip.
84       
85        if (!node.GetChildByRole(Roles.Identifier).IsNull) {
86          // We'll suppress the tooltip for resolvable nodes if there is an identifier that
87          // could be hovered over instead:
88          return null;
89        }
90      }
91
92      if (node == null)
93        return null;
94      if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) {
95        node = node.Parent;
96      } else if (node is ThisReferenceExpression && node.Parent is IndexerExpression) {
97        node = node.Parent;
98      }
99
100      InvocationExpression parentInvocation = null;
101      if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument) {
102        // we also need to resolve the invocation
103        parentInvocation = node.Parent as InvocationExpression;
104      }
105     
106      // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused
107      CSharpAstResolver resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile);
108      ResolveResult rr = resolver.Resolve(node, cancellationToken);
109      MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult;
110      if (mgrr != null) {
111        // For method groups, resolve the parent invocation instead.
112        if (parentInvocation != null)
113          return resolver.Resolve(parentInvocation);
114        if (node is Expression) {
115          // If it's not an invocation, try if it's a conversion to a delegate type:
116          Conversion c = resolver.GetConversion((Expression)node, cancellationToken);
117          if (c.IsMethodGroupConversion)
118            return new MemberResolveResult(mgrr.TargetResult, c.Method);
119        }
120      }
121      return rr;
122    }
123  }
124}
Note: See TracBrowser for help on using the repository browser.