提交 bff28be0 编写于 作者: J Jason Malinowski

Null annotate the RQName code

This annotation revealed a number of places where if some part of RQName
generation failed, we'd end up creating RQNode objects with null fields;
trying to convert that to the text would end up crashing. This adds
proper error handling when issues were discovered by analysis.
上级 5f47351b
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
{
internal abstract class RQArrayOrPointerType : RQType
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
{
internal class RQEvent : RQMethodPropertyOrEvent
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......@@ -11,7 +13,6 @@ internal abstract class RQParameter
public readonly RQType Type;
public RQParameter(RQType type)
{
System.Diagnostics.Debug.Assert(type != null);
Type = type;
}
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName.Nodes
{
internal abstract class RQNode<ResolvedType> : UnresolvedRQNode
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Text;
using Microsoft.CodeAnalysis.Features.RQName.SimpleTree;
......@@ -11,11 +13,6 @@ internal static class ParenthesesTreeWriter
{
public static string ToParenthesesFormat(SimpleTreeNode tree)
{
if (tree == null)
{
return null;
}
var sb = new StringBuilder();
WriteNode(tree, sb);
return sb.ToString();
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName
{
/// <summary>
......@@ -13,10 +15,16 @@ internal static class RQNameInternal
/// Returns an RQName for the given symbol, or <see langword="null"/> if the symbol cannot be represented by an RQName.
/// </summary>
/// <param name="symbol">The symbol to build an RQName for.</param>
public static string From(ISymbol symbol)
public static string? From(ISymbol symbol)
{
var node = RQNodeBuilder.Build(symbol);
return ParenthesesTreeWriter.ToParenthesesFormat(node?.ToSimpleTree());
if (node == null)
{
return null;
}
return ParenthesesTreeWriter.ToParenthesesFormat(node.ToSimpleTree());
}
}
}
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName
{
internal sealed class RQNameStrings
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
......@@ -16,15 +18,15 @@ internal static class RQNodeBuilder
/// Builds the RQName for a given symbol.
/// </summary>
/// <returns>The node if it could be created, otherwise null</returns>
public static UnresolvedRQNode Build(ISymbol symbol)
=> symbol.Kind switch
public static UnresolvedRQNode? Build(ISymbol symbol)
=> symbol switch
{
SymbolKind.Namespace => BuildNamespace(symbol as INamespaceSymbol),
SymbolKind.NamedType => BuildNamedType(symbol as INamedTypeSymbol),
SymbolKind.Method => BuildMethod(symbol as IMethodSymbol),
SymbolKind.Field => BuildField(symbol as IFieldSymbol),
SymbolKind.Event => BuildEvent(symbol as IEventSymbol),
SymbolKind.Property => BuildProperty(symbol as IPropertySymbol),
INamespaceSymbol namespaceSymbol => BuildNamespace(namespaceSymbol),
INamedTypeSymbol namedTypeSymbol => BuildUnconstructedNamedType(namedTypeSymbol),
IMethodSymbol methodSymbol => BuildMethod(methodSymbol),
IFieldSymbol fieldSymbol => BuildField(fieldSymbol),
IEventSymbol eventSymbol => BuildEvent(eventSymbol),
IPropertySymbol propertySymbol => BuildProperty(propertySymbol),
_ => null,
};
......@@ -50,7 +52,7 @@ private static IList<string> GetNameParts(INamespaceSymbol @namespace)
return parts;
}
private static RQUnconstructedType BuildNamedType(INamedTypeSymbol type)
private static RQUnconstructedType? BuildUnconstructedNamedType(INamedTypeSymbol type)
{
// Anything that is a valid RQUnconstructed types is ALWAYS safe for public APIs
......@@ -84,9 +86,9 @@ private static RQUnconstructedType BuildNamedType(INamedTypeSymbol type)
return new RQUnconstructedType(namespaceNames, typeInfos);
}
private static RQMember BuildField(IFieldSymbol symbol)
private static RQMember? BuildField(IFieldSymbol symbol)
{
var containingType = BuildNamedType(symbol.ContainingType);
var containingType = BuildUnconstructedNamedType(symbol.ContainingType);
if (containingType == null)
{
......@@ -96,7 +98,7 @@ private static RQMember BuildField(IFieldSymbol symbol)
return new RQMemberVariable(containingType, symbol.Name);
}
private static RQProperty BuildProperty(IPropertySymbol symbol)
private static RQProperty? BuildProperty(IPropertySymbol symbol)
{
RQMethodPropertyOrEventName name = symbol.IsIndexer ?
RQOrdinaryMethodPropertyOrEventName.CreateOrdinaryIndexerName() :
......@@ -109,12 +111,17 @@ private static RQProperty BuildProperty(IPropertySymbol symbol)
return null;
}
name = new RQExplicitInterfaceMemberName(
BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType as ITypeSymbol),
(RQOrdinaryMethodPropertyOrEventName)name);
var interfaceType = BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType);
if (interfaceType != null)
{
name = new RQExplicitInterfaceMemberName(
interfaceType,
(RQOrdinaryMethodPropertyOrEventName)name);
}
}
var containingType = BuildNamedType(symbol.ContainingType);
var containingType = BuildUnconstructedNamedType(symbol.ContainingType);
if (containingType == null)
{
......@@ -123,10 +130,15 @@ private static RQProperty BuildProperty(IPropertySymbol symbol)
var parameterList = BuildParameterList(symbol.Parameters);
if (parameterList == null)
{
return null;
}
return new RQProperty(containingType, name, typeParameterCount: 0, parameters: parameterList);
}
private static IList<RQParameter> BuildParameterList(ImmutableArray<IParameterSymbol> parameters)
private static IList<RQParameter>? BuildParameterList(ImmutableArray<IParameterSymbol> parameters)
{
var parameterList = new List<RQParameter>();
......@@ -134,6 +146,11 @@ private static IList<RQParameter> BuildParameterList(ImmutableArray<IParameterSy
{
var parameterType = BuildType(parameter.Type);
if (parameterType == null)
{
return null;
}
if (parameter.RefKind == RefKind.Out)
{
parameterList.Add(new RQOutParameter(parameterType));
......@@ -151,9 +168,9 @@ private static IList<RQParameter> BuildParameterList(ImmutableArray<IParameterSy
return parameterList;
}
private static RQEvent BuildEvent(IEventSymbol symbol)
private static RQEvent? BuildEvent(IEventSymbol symbol)
{
var containingType = BuildNamedType(symbol.ContainingType);
var containingType = BuildUnconstructedNamedType(symbol.ContainingType);
if (containingType == null)
{
......@@ -169,13 +186,18 @@ private static RQEvent BuildEvent(IEventSymbol symbol)
return null;
}
name = new RQExplicitInterfaceMemberName(BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType as ITypeSymbol), (RQOrdinaryMethodPropertyOrEventName)name);
var interfaceType = BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType);
if (interfaceType != null)
{
name = new RQExplicitInterfaceMemberName(interfaceType, (RQOrdinaryMethodPropertyOrEventName)name);
}
}
return new RQEvent(containingType, name);
}
private static RQMethod BuildMethod(IMethodSymbol symbol)
private static RQMethod? BuildMethod(IMethodSymbol symbol)
{
if (symbol.MethodKind == MethodKind.UserDefinedOperator ||
symbol.MethodKind == MethodKind.BuiltinOperator ||
......@@ -209,10 +231,15 @@ private static RQMethod BuildMethod(IMethodSymbol symbol)
return null;
}
name = new RQExplicitInterfaceMemberName(BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType as ITypeSymbol), (RQOrdinaryMethodPropertyOrEventName)name);
var interfaceType = BuildType(symbol.ExplicitInterfaceImplementations.Single().ContainingType);
if (interfaceType != null)
{
name = new RQExplicitInterfaceMemberName(interfaceType, (RQOrdinaryMethodPropertyOrEventName)name);
}
}
var containingType = BuildNamedType(symbol.ContainingType);
var containingType = BuildUnconstructedNamedType(symbol.ContainingType);
if (containingType == null)
{
......@@ -222,10 +249,15 @@ private static RQMethod BuildMethod(IMethodSymbol symbol)
var typeParamCount = symbol.TypeParameters.Length;
var parameterList = BuildParameterList(symbol.Parameters);
if (parameterList == null)
{
return null;
}
return new RQMethod(containingType, name, typeParamCount, parameterList);
}
private static RQType BuildType(ITypeSymbol symbol)
private static RQType? BuildType(ITypeSymbol symbol)
{
if (symbol.IsAnonymousType)
{
......@@ -236,13 +268,25 @@ private static RQType BuildType(ITypeSymbol symbol)
{
return RQVoidType.Singleton;
}
else if (symbol.TypeKind == TypeKind.Pointer)
else if (symbol is IPointerTypeSymbol pointerType)
{
return new RQPointerType(BuildType((symbol as IPointerTypeSymbol).PointedAtType));
var pointedAtType = BuildType(pointerType.PointedAtType);
if (pointedAtType == null)
{
return null;
}
return new RQPointerType(pointedAtType);
}
else if (symbol.TypeKind == TypeKind.Array)
else if (symbol is IArrayTypeSymbol arrayType)
{
return new RQArrayType((symbol as IArrayTypeSymbol).Rank, BuildType((symbol as IArrayTypeSymbol).ElementType));
var elementType = BuildType(arrayType.ElementType);
if (elementType == null)
{
return null;
}
return new RQArrayType(arrayType.Rank, elementType);
}
else if (symbol.TypeKind == TypeKind.TypeParameter)
{
......@@ -259,10 +303,8 @@ private static RQType BuildType(ITypeSymbol symbol)
// not, we just erase dynamic to object here.
return RQType.ObjectType;
}
else if (symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.ErrorType)
else if (symbol is INamedTypeSymbol namedTypeSymbol)
{
var namedTypeSymbol = symbol as INamedTypeSymbol;
var definingType = namedTypeSymbol.ConstructedFrom ?? namedTypeSymbol;
var typeChain = new List<INamedTypeSymbol>();
......@@ -283,11 +325,17 @@ private static RQType BuildType(ITypeSymbol symbol)
{
foreach (var typeArgument in entry.TypeArguments)
{
typeArgumentList.Add(BuildType(typeArgument));
var rqType = BuildType(typeArgument);
if (rqType == null)
{
return null;
}
typeArgumentList.Add(rqType);
}
}
var containingType = BuildNamedType(definingType);
var containingType = BuildUnconstructedNamedType(definingType);
if (containingType == null)
{
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System.Collections.Generic;
using System.Linq;
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName.SimpleTree
{
internal class SimpleLeafNode : SimpleTreeNode
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace Microsoft.CodeAnalysis.Features.RQName.SimpleTree
{
internal abstract class SimpleTreeNode
......
......@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Features.RQName;
using Microsoft.VisualStudio.Shell.Interop;
......@@ -20,7 +22,7 @@ public static class RQName
/// <param name="symbol">The symbol to build an RQName for.</param>
/// <returns>A string suitable to pass as the pszRQName argument to methods in <see cref="IVsRefactorNotify"/>
/// and <see cref="IVsSymbolicNavigationNotify"/>.</returns>
public static string From(ISymbol symbol)
public static string? From(ISymbol symbol)
=> RQNameInternal.From(symbol);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册