“b11956a0b56a293cfcf96e9810e1490c33ea7b07”上不存在“python/paddle/fluid/contrib/slim/tests/CMakeLists.txt”
SyntaxTreeInfo.cs 14.7 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6 7

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
8
using Microsoft.CodeAnalysis.ErrorReporting;
P
Pilchie 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.FindSymbols
{
    internal partial class SyntaxTreeInfo
    {
        /// <summary>
        /// snapshot based cache to guarantee same info is returned without re-calculating for same solution snapshot.
        /// since document will be re-created per new solution, this should go away as soon as there is any change on workspace.
        /// </summary>
22 23 24
        private static readonly ConditionalWeakTable<Document, SyntaxTreeIdentifierInfo> s_identifierSnapshotCache = new ConditionalWeakTable<Document, SyntaxTreeIdentifierInfo>();
        private static readonly ConditionalWeakTable<Document, SyntaxTreeContextInfo> s_contextSnapshotCache = new ConditionalWeakTable<Document, SyntaxTreeContextInfo>();
        private static readonly ConditionalWeakTable<Document, SyntaxTreeDeclarationInfo> s_declaredSymbolsSnapshotCache = new ConditionalWeakTable<Document, SyntaxTreeDeclarationInfo>();
P
Pilchie 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

        public static async Task PrecalculateAsync(Document document, CancellationToken cancellationToken)
        {
            Contract.Requires(document.IsFromPrimaryBranch());

            await PrecalculateBasicInfoAsync(document, cancellationToken).ConfigureAwait(false);

            // for now, don't put identifier locations in esent db
            //// await PrecalculateAdvancedInfoAsync(document, cancellationToken).ConfigureAwait(false);
        }

        private static async Task PrecalculateAdvancedInfoAsync(Document document, CancellationToken cancellationToken)
        {
            // we do not support precalculating opened file.
            if (document.IsOpen())
            {
                return;
            }

            // we already have information. move on
            if (await SyntaxTreeIdentifierInfo.IdentifierSetPrecalculatedAsync(document, cancellationToken).ConfigureAwait(false))
            {
                return;
            }

            await SyntaxTreeIdentifierInfo.SaveIdentifierSetAsync(document, cancellationToken).ConfigureAwait(false);
        }

        private static async Task PrecalculateBasicInfoAsync(Document document, CancellationToken cancellationToken)
        {
            // we already have information. move on
            if (await SyntaxTreeIdentifierInfo.PrecalculatedAsync(document, cancellationToken).ConfigureAwait(false) &&
B
brettv 已提交
57 58
                await SyntaxTreeContextInfo.PrecalculatedAsync(document, cancellationToken).ConfigureAwait(false) &&
                await SyntaxTreeDeclarationInfo.PrecalculatedAsync(document, cancellationToken).ConfigureAwait(false))
P
Pilchie 已提交
59 60 61 62 63 64 65 66
            {
                return;
            }

            var data = await CreateInfoAsync(document, cancellationToken).ConfigureAwait(false);

            await data.Item1.SaveAsync(document, cancellationToken).ConfigureAwait(false);
            await data.Item2.SaveAsync(document, cancellationToken).ConfigureAwait(false);
B
brettv 已提交
67
            await data.Item3.SaveAsync(document, cancellationToken).ConfigureAwait(false);
P
Pilchie 已提交
68 69
        }

B
brettv 已提交
70 71 72 73 74 75 76
        private static async Task<T> GetInfoAsync<T>(
            Document document,
            ConditionalWeakTable<Document, T> cache,
            Func<Document, CancellationToken, Task<T>> generator,
            Func<ValueTuple<SyntaxTreeIdentifierInfo, SyntaxTreeContextInfo, SyntaxTreeDeclarationInfo>, T> selector,
            CancellationToken cancellationToken)
            where T : class
P
Pilchie 已提交
77
        {
B
brettv 已提交
78 79
            T info;
            if (cache.TryGetValue(document, out info))
P
Pilchie 已提交
80 81 82 83
            {
                return info;
            }

B
brettv 已提交
84
            info = await generator(document, cancellationToken).ConfigureAwait(false);
P
Pilchie 已提交
85 86
            if (info != null)
            {
B
brettv 已提交
87
                return cache.GetValue(document, _ => info);
P
Pilchie 已提交
88 89
            }

B
brettv 已提交
90
            // alright, we don't have cached information, re-calculate them here.
P
Pilchie 已提交
91 92
            var data = await CreateInfoAsync(document, cancellationToken).ConfigureAwait(false);

B
brettv 已提交
93
            // okay, persist this info
P
Pilchie 已提交
94 95
            await data.Item1.SaveAsync(document, cancellationToken).ConfigureAwait(false);
            await data.Item2.SaveAsync(document, cancellationToken).ConfigureAwait(false);
B
brettv 已提交
96
            await data.Item3.SaveAsync(document, cancellationToken).ConfigureAwait(false);
P
Pilchie 已提交
97

B
brettv 已提交
98 99
            info = selector(data);
            return cache.GetValue(document, _ => info);
P
Pilchie 已提交
100 101
        }

B
brettv 已提交
102
        public static Task<SyntaxTreeContextInfo> GetContextInfoAsync(Document document, CancellationToken cancellationToken)
P
Pilchie 已提交
103
        {
104
            return GetInfoAsync(document, s_contextSnapshotCache, SyntaxTreeContextInfo.LoadAsync, tuple => tuple.Item2, cancellationToken);
B
brettv 已提交
105
        }
P
Pilchie 已提交
106

B
brettv 已提交
107 108
        public static Task<SyntaxTreeIdentifierInfo> GetIdentifierInfoAsync(Document document, CancellationToken cancellationToken)
        {
109
            return GetInfoAsync(document, s_identifierSnapshotCache, SyntaxTreeIdentifierInfo.LoadAsync, tuple => tuple.Item1, cancellationToken);
B
brettv 已提交
110
        }
P
Pilchie 已提交
111

B
brettv 已提交
112 113
        public static Task<SyntaxTreeDeclarationInfo> GetDeclarationInfoAsync(Document document, CancellationToken cancellationToken)
        {
114
            return GetInfoAsync(document, s_declaredSymbolsSnapshotCache, SyntaxTreeDeclarationInfo.LoadAsync, tuple => tuple.Item3, cancellationToken);
P
Pilchie 已提交
115 116 117 118 119
        }

        // The probability of getting a false positive when calling ContainsIdentifier.
        private const double FalsePositiveProbability = 0.0001;

B
brettv 已提交
120
        private static async Task<ValueTuple<SyntaxTreeIdentifierInfo, SyntaxTreeContextInfo, SyntaxTreeDeclarationInfo>> CreateInfoAsync(Document document, CancellationToken cancellationToken)
P
Pilchie 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
        {
            var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
            var ignoreCase = syntaxFacts != null && !syntaxFacts.IsCaseSensitive;
            var isCaseSensitive = !ignoreCase;

            HashSet<string> identifiers;
            HashSet<string> escapedIdentifiers;
            GetIdentifierSet(ignoreCase, out identifiers, out escapedIdentifiers);

            try
            {
                var containsForEachStatement = false;
                var containsLockStatement = false;
                var containsUsingStatement = false;
                var containsQueryExpression = false;
                var containsThisConstructorInitializer = false;
                var containsBaseConstructorInitializer = false;
                var containsElementAccess = false;
                var containsIndexerMemberCref = false;

                var predefinedTypes = (int)PredefinedType.None;
                var predefinedOperators = (int)PredefinedOperator.None;

B
brettv 已提交
144 145
                var declaredSymbolInfos = new List<DeclaredSymbolInfo>();

P
Pilchie 已提交
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
                if (syntaxFacts != null)
                {
                    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                    foreach (var current in root.DescendantNodesAndTokensAndSelf(descendIntoTrivia: true))
                    {
                        if (current.IsNode)
                        {
                            var node = (SyntaxNode)current;

                            containsForEachStatement = containsForEachStatement || syntaxFacts.IsForEachStatement(node);
                            containsLockStatement = containsLockStatement || syntaxFacts.IsLockStatement(node);
                            containsUsingStatement = containsUsingStatement || syntaxFacts.IsUsingStatement(node);
                            containsQueryExpression = containsQueryExpression || syntaxFacts.IsQueryExpression(node);
                            containsElementAccess = containsElementAccess || syntaxFacts.IsElementAccessExpression(node);
                            containsIndexerMemberCref = containsIndexerMemberCref || syntaxFacts.IsIndexerMemberCRef(node);
B
brettv 已提交
162

163 164 165 166 167 168 169 170 171
                            // We've received a number of error reports where DeclaredSymbolInfo.GetSymbolAsync() will
                            // crash because the document's syntax root doesn't contain the span of the node returned
                            // by TryGetDeclaredSymbolInfo().  There are two possibilities for this crash:
                            //   1) syntaxFacts.TryGetDeclaredSymbolInfo() is returning a bad span, or
                            //   2) Document.GetSyntaxRootAsync() (called from DeclaredSymbolInfo.GetSymbolAsync) is
                            //      returning a bad syntax root that doesn't represent the original parsed document.
                            // By adding the `root.FullSpan.Contains()` check below, if we get similar crash reports in
                            // the future then we know the problem lies in (2).  If, however, the problem is really in
                            // TryGetDeclaredSymbolInfo, then this will at least prevent us from returning bad spans
C
Charles Stoner 已提交
172
                            // and will prevent the crash from occurring.
B
brettv 已提交
173
                            DeclaredSymbolInfo declaredSymbolInfo;
174
                            if (syntaxFacts.TryGetDeclaredSymbolInfo(node, out declaredSymbolInfo))
B
brettv 已提交
175
                            {
176 177 178 179 180 181 182 183 184 185 186 187
                                if (root.FullSpan.Contains(declaredSymbolInfo.Span))
                                {
                                    declaredSymbolInfos.Add(declaredSymbolInfo);
                                }
                                else
                                {
                                    var message =
$@"Invalid span in {nameof(declaredSymbolInfo)}.
{nameof(declaredSymbolInfo.Span)} = {declaredSymbolInfo.Span}
{nameof(root.FullSpan)} = {root.FullSpan}";
                                    FatalError.ReportWithoutCrash(new InvalidOperationException(message));
                                }
B
brettv 已提交
188
                            }
P
Pilchie 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
                        }
                        else
                        {
                            var token = (SyntaxToken)current;

                            containsThisConstructorInitializer = containsThisConstructorInitializer || syntaxFacts.IsThisConstructorInitializer(token);
                            containsBaseConstructorInitializer = containsBaseConstructorInitializer || syntaxFacts.IsBaseConstructorInitializer(token);

                            if (syntaxFacts.IsIdentifier(token) || syntaxFacts.IsGlobalNamespaceKeyword(token))
                            {
                                var valueText = token.ValueText;

                                identifiers.Add(valueText);
                                if (valueText.Length != token.Width())
                                {
                                    escapedIdentifiers.Add(valueText);
                                }
                            }

                            PredefinedType predefinedType;
                            if (syntaxFacts.TryGetPredefinedType(token, out predefinedType))
                            {
                                predefinedTypes |= (int)predefinedType;
                            }

                            PredefinedOperator predefinedOperator;
                            if (syntaxFacts.TryGetPredefinedOperator(token, out predefinedOperator))
                            {
                                predefinedOperators |= (int)predefinedOperator;
                            }
                        }
                    }
                }

                var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false);

                return ValueTuple.Create(
                    new SyntaxTreeIdentifierInfo(
                        version,
                        new BloomFilter(FalsePositiveProbability, isCaseSensitive, identifiers),
                        new BloomFilter(FalsePositiveProbability, isCaseSensitive, escapedIdentifiers)),
                    new SyntaxTreeContextInfo(
                        version,
                        predefinedTypes,
                        predefinedOperators,
                        containsForEachStatement,
                        containsLockStatement,
                        containsUsingStatement,
                        containsQueryExpression,
                        containsThisConstructorInitializer,
                        containsBaseConstructorInitializer,
                        containsElementAccess,
B
brettv 已提交
241 242 243 244
                        containsIndexerMemberCref),
                    new SyntaxTreeDeclarationInfo(
                        version,
                        declaredSymbolInfos));
P
Pilchie 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
            }
            finally
            {
                Free(ignoreCase, identifiers, escapedIdentifiers);
            }
        }

        private static void GetIdentifierSet(bool ignoreCase, out HashSet<string> identifiers, out HashSet<string> escapedIdentifiers)
        {
            if (ignoreCase)
            {
                identifiers = SharedPools.StringIgnoreCaseHashSet.AllocateAndClear();
                escapedIdentifiers = SharedPools.StringIgnoreCaseHashSet.AllocateAndClear();

                Contract.Requires(identifiers.Comparer == StringComparer.OrdinalIgnoreCase);
                Contract.Requires(escapedIdentifiers.Comparer == StringComparer.OrdinalIgnoreCase);
                return;
            }

            identifiers = SharedPools.StringHashSet.AllocateAndClear();
            escapedIdentifiers = SharedPools.StringHashSet.AllocateAndClear();

            Contract.Requires(identifiers.Comparer == StringComparer.Ordinal);
            Contract.Requires(escapedIdentifiers.Comparer == StringComparer.Ordinal);
        }

        private static void Free(bool ignoreCase, HashSet<string> identifiers, HashSet<string> escapedIdentifiers)
        {
            if (ignoreCase)
            {
                Contract.Requires(identifiers.Comparer == StringComparer.OrdinalIgnoreCase);
                Contract.Requires(escapedIdentifiers.Comparer == StringComparer.OrdinalIgnoreCase);

                SharedPools.StringIgnoreCaseHashSet.ClearAndFree(identifiers);
                SharedPools.StringIgnoreCaseHashSet.ClearAndFree(escapedIdentifiers);
                return;
            }

            Contract.Requires(identifiers.Comparer == StringComparer.Ordinal);
            Contract.Requires(escapedIdentifiers.Comparer == StringComparer.Ordinal);

            SharedPools.StringHashSet.ClearAndFree(identifiers);
            SharedPools.StringHashSet.ClearAndFree(escapedIdentifiers);
        }
    }
290
}