Exemple #1
1
        private SDProperty GetParsedProperty(IPropertySymbol property)
        {
            var syntaxReference = property.DeclaringSyntaxReferences.Any() ? property.DeclaringSyntaxReferences.Single() : null;
            var sdProperty = new SDProperty(property.GetIdentifier())
            {
                Name = property.Name,
                DeclaringType = _typeRefParser.GetParsedTypeReference(property.ContainingType),
                Accessibility = property.DeclaredAccessibility.ToString().ToLower(),
                ReturnType = _typeRefParser.GetParsedTypeReference(property.Type),
                CanGet = property.GetMethod != null,
                CanSet = property.SetMethod != null,
                IsAbstract = property.IsAbstract,
                IsVirtual = property.IsVirtual,
                IsOverride = property.IsOverride,
                Documentations = DocumentationParser.ParseDocumentation(property),
                Region = syntaxReference != null ? new SDRegion
                {
                    Start = syntaxReference.Span.Start,
                    End = syntaxReference.Span.End,
                    StartLine = syntaxReference.SyntaxTree.GetLineSpan(syntaxReference.Span).StartLinePosition.Line + 1,
                    EndLine = syntaxReference.SyntaxTree.GetLineSpan(syntaxReference.Span).EndLinePosition.Line + 1,
                    FilePath = syntaxReference.SyntaxTree.FilePath,
                    Filename = Path.GetFileName(syntaxReference.SyntaxTree.FilePath)
                } : null
            };

            ParserOptions.SDRepository.AddMember(sdProperty);
            return sdProperty;
        }
            private IMethodSymbol GenerateSetAccessor(
                Compilation compilation,
                IPropertySymbol property,
                Accessibility accessibility,
                bool generateAbstractly,
                bool useExplicitInterfaceSymbol,
                INamedTypeSymbol[] attributesToRemove,
                CancellationToken cancellationToken)
            {
                if (property.SetMethod == null)
                {
                    return null;
                }

                var setMethod = property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
                     this.State.ClassOrStructType,
                     attributesToRemove);

                return CodeGenerationSymbolFactory.CreateAccessorSymbol(
                    setMethod,
                    attributes: null,
                    accessibility: accessibility,
                    explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null,
                    statements: GetSetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
            }
 internal static IPropertySymbol CreatePropertySymbol(
     INamedTypeSymbol containingType,
     IList<AttributeData> attributes,
     Accessibility accessibility,
     DeclarationModifiers modifiers,
     ITypeSymbol type,
     IPropertySymbol explicitInterfaceSymbol,
     string name,
     IList<IParameterSymbol> parameters,
     IMethodSymbol getMethod,
     IMethodSymbol setMethod,
     bool isIndexer = false,
     SyntaxNode initializer = null)
 {
     var result = new CodeGenerationPropertySymbol(
         containingType,
         attributes,
         accessibility,
         modifiers,
         type,
         explicitInterfaceSymbol,
         name,
         isIndexer,
         parameters,
         getMethod,
         setMethod);
     CodeGenerationPropertyInfo.Attach(result, modifiers.IsNew, modifiers.IsUnsafe, initializer);
     return result;
 }
        public virtual SimilarityRank<IPropertySymbol> FindSimilarityRank(IPropertySymbol sourceProperty, IEnumerable<IPropertySymbol> targetProperties, List<IClassPropertyComparer> allComparers)
        {
            var allMatches = FindAllMatches(sourceProperty, targetProperties, allComparers);
            var topMatch = allMatches.OrderByDescending(r => r.Confidence).FirstOrDefault(r => r.Confidence > 0);

            return (topMatch ?? new SimilarityRank<IPropertySymbol>());
        }
 internal void HandleValueField(ValueField valueField, IPropertySymbol property, ImmutableArray<AttributeData> propertyAttributes)
 {
     AddKeyAttribute(property, propertyAttributes, valueField);
     AddIndexAttribute(property, propertyAttributes, valueField);
     AddMaxLengthAttribute(property, propertyAttributes, valueField);
     AddDatabaseGeneratedAttribute(property, propertyAttributes, valueField);
 }
 public static void Create(IPropertySymbol symbol, SymbolKeyWriter visitor)
 {
     visitor.WriteString(symbol.MetadataName);
     visitor.WriteSymbolKey(symbol.ContainingSymbol);
     visitor.WriteBoolean(symbol.IsIndexer);
     visitor.WriteRefKindArray(symbol.Parameters);
     visitor.WriteParameterTypesArray(symbol.OriginalDefinition.Parameters);
 }
 public static void Attach(
     IPropertySymbol property,
     bool isNew,
     bool isUnsafe)
 {
     var info = new CodeGenerationPropertyInfo(isNew, isUnsafe);
     propertyToInfoMap.Add(property, info);
 }
        public SimilarityRank<IPropertySymbol> Compare(IPropertySymbol sourceProperty, IPropertySymbol targetProperty)
        {
            //TODO: check for subclasses
            bool sameType = sourceProperty.Type.Equals(targetProperty.Type);
            int confidence = (sameType ? 100 : 0);

            return new SimilarityRank<IPropertySymbol>() { Confidence = confidence, Symbol = targetProperty };
        }
 public static void Attach(
     IPropertySymbol property,
     bool isNew,
     bool isUnsafe,
     SyntaxNode initializer)
 {
     var info = new CodeGenerationPropertyInfo(isNew, isUnsafe, initializer);
     s_propertyToInfoMap.Add(property, info);
 }
		public static bool HaveSameSignature (IPropertySymbol property1, IPropertySymbol property2, bool caseSensitive)
		{
			try {
				return (bool)haveSameSignature2Method.Invoke(instance, new object[] { property1, property2, caseSensitive });
			} catch (TargetInvocationException ex) {
				ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
				return false;
			}
		}
        protected override void ReadSymbol(IPropertySymbol propertySymbol)
        {
            // we don't need to know about static members
            // because they won't be delegated from child to mixin
            if (propertySymbol.IsStatic)
                return;

            // we ignore private and protected memebers
            var hasGetter = propertySymbol.GetMethod != null &&
                      !(propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Protected);
            var hasSetter = propertySymbol.SetMethod != null &&
                      !(propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Private ||
                        propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Protected);

            // property has no accessors or accessors are not accessible => skip property
            if (!hasSetter && !hasGetter)
                return;

            Property property = null;

            if (propertySymbol.IsIndexer) // symbol is an indexer property
            {
                var indexerProperty = new IndexerProperty(
                    propertySymbol.Type,
                    hasGetter,
                    hasSetter);
                var parameterReader = new ParameterSymbolReader(indexerProperty);
                parameterReader.VisitSymbol(propertySymbol);
                property = indexerProperty;
            }
            else // symbol is a normal property
            {
                property = new Property(
                    propertySymbol.Name,
                    propertySymbol.Type,
                    hasGetter,
                    hasSetter);
            }
            property.IsAbstract = propertySymbol.IsAbstract;
            property.IsOverride = propertySymbol.IsOverride;

            // store information if accessors are internal,
            // we will need this for the generation later
            property.IsGetterInternal = hasGetter &&
                                        propertySymbol.GetMethod
                                        .DeclaredAccessibility.HasFlag(Accessibility.Internal);
            property.IsSetterInternal = hasSetter &&
                                        propertySymbol.SetMethod
                                        .DeclaredAccessibility.HasFlag(Accessibility.Internal);
                    
            property.Documentation = new DocumentationComment(propertySymbol.GetDocumentationCommentXml());

            _properties.AddProperty(property);
        }
        private List<SimilarityRank<IPropertySymbol>> FindAllMatches(IPropertySymbol sourceProperty, IEnumerable<IPropertySymbol> targetProperties, List<IClassPropertyComparer> allComparers)
        {
            var allMatches = new List<SimilarityRank<IPropertySymbol>>();

            foreach (var comparer in allComparers)
            {
                allMatches.AddRange(FindMatches(sourceProperty, targetProperties, comparer));
            }

            return allMatches;
        }
Exemple #13
0
        internal static CompilationUnitSyntax AddPropertyTo(
            CompilationUnitSyntax destination,
            IPropertySymbol property,
            CodeGenerationOptions options,
            IList<bool> availableIndices)
        {
            var declaration = GeneratePropertyOrIndexer(property, CodeGenerationDestination.CompilationUnit, options);

            var members = Insert(destination.Members, declaration, options,
                availableIndices, after: LastPropertyOrField, before: FirstMember);
            return destination.WithMembers(members);
        }
        private SimilarityRank<IPropertySymbol> CompoundCompare(IPropertySymbol sourceProperty, IPropertySymbol targetProperty, IEnumerable<IClassPropertyComparer> comparers)
        {
            List<SimilarityRank<IPropertySymbol>> allResultRanks = new List<SimilarityRank<IPropertySymbol>>();
            foreach (var propertyComparer in comparers)
            {
                SimilarityRank<IPropertySymbol> rank = propertyComparer.Compare(sourceProperty, targetProperty);

                allResultRanks.Add(rank);
            }

            return BuildCombinedRank(targetProperty, allResultRanks);
        }
            private ISymbol GenerateProperty(
                Compilation compilation,
                IPropertySymbol property,
                Accessibility accessibility,
                DeclarationModifiers modifiers,
                bool generateAbstractly,
                bool useExplicitInterfaceSymbol,
                string memberName,
                CancellationToken cancellationToken)
            {
                var factory = this.Document.GetLanguageService<SyntaxGenerator>();
                var comAliasNameAttribute = compilation.ComAliasNameAttributeType();

                var getAccessor = property.GetMethod == null
                    ? null
                    : CodeGenerationSymbolFactory.CreateAccessorSymbol(
                        property.GetMethod.RemoveInaccessibleAttributesAndAttributesOfType(
                            accessibleWithin: this.State.ClassOrStructType,
                            removeAttributeType: comAliasNameAttribute),
                        attributes: null,
                        accessibility: accessibility,
                        explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.GetMethod : null,
                        statements: GetGetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));

                var setAccessor = property.SetMethod == null
                    ? null
                    : CodeGenerationSymbolFactory.CreateAccessorSymbol(
                        property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfType(
                            accessibleWithin: this.State.ClassOrStructType,
                            removeAttributeType: comAliasNameAttribute),
                        attributes: null,
                        accessibility: accessibility,
                        explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null,
                        statements: GetSetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));

                var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
                var parameterNames = NameGenerator.EnsureUniqueness(
                    property.Parameters.Select(p => p.Name).ToList(), isCaseSensitive: syntaxFacts.IsCaseSensitive);

                var updatedProperty = property.RenameParameters(parameterNames);

                updatedProperty = updatedProperty.RemoveAttributeFromParameters(comAliasNameAttribute);

                // TODO(cyrusn): Delegate through throughMember if it's non-null.
                return CodeGenerationSymbolFactory.CreatePropertySymbol(
                    updatedProperty,
                    accessibility: accessibility,
                    modifiers: modifiers,
                    explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property : null,
                    name: memberName,
                    getMethod: getAccessor,
                    setMethod: setAccessor);
            }
Exemple #16
0
 internal ForEachSymbols(IMethodSymbol getEnumeratorMethod,
                         IMethodSymbol moveNextMethod,
                         IPropertySymbol currentProperty,
                         IMethodSymbol disposeMethod,
                         ITypeSymbol elementType)
     : this()
 {
     this.GetEnumeratorMethod = getEnumeratorMethod;
     this.MoveNextMethod = moveNextMethod;
     this.CurrentProperty = currentProperty;
     this.DisposeMethod = disposeMethod;
     this.ElementType = elementType;
 }
Exemple #17
0
        public bool HaveSameSignature(IPropertySymbol property1, IPropertySymbol property2, bool caseSensitive)
        {
            if (!IdentifiersMatch(property1.Name, property2.Name, caseSensitive) ||
                property1.Parameters.Length != property2.Parameters.Length ||
                property1.IsIndexer != property2.IsIndexer)
            {
                return false;
            }

            return property1.Parameters.SequenceEqual(
                property2.Parameters,
                this.ParameterEquivalenceComparer);
        }
        private void AddHasForeignKeyAttribute(IPropertySymbol classProperty, IEnumerable<AttributeData> propertyAttributes, SingleField singleField)
        {
            var foreignKeyAttribute = propertyAttributes.SingleOrDefault(a => a.AttributeClass.Name == "HasForeignKeyAttribute");

            var foreignKeyAttributeString = "-";
            if (foreignKeyAttribute != null)
            {
                foreignKeyAttributeString = (string)foreignKeyAttribute.ConstructorArguments[0].Value;
            }

            var assumption = _constraintBuilder.Assume(() => singleField.ForeignKeyAttribute == foreignKeyAttributeString);
            _propertyAssumptions.Add(new HasForeignKeyAttributePropertyAssumption(classProperty, assumption, singleField));
        }
        private void AddDatabaseGeneratedAttribute(IPropertySymbol classProperty, IEnumerable<AttributeData> propertyAttributes, ValueField valueField)
        {
            var databaseGeneratedAttributeValue = DatabaseGeneratedAttribute.None;

            var databaseGeneratedAttribute = propertyAttributes.SingleOrDefault(a => a.AttributeClass.Name == "DatabaseGeneratedAttribute");
            if (databaseGeneratedAttribute != null)
            {
                var databaseGeneratedOption = Enum.GetName(typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption), databaseGeneratedAttribute.ConstructorArguments[0].Value);
                databaseGeneratedAttributeValue = (DatabaseGeneratedAttribute)Enum.Parse(typeof(DatabaseGeneratedAttribute), databaseGeneratedOption);
            }

            var assumption = _constraintBuilder.Assume(() => valueField.DatabaseGeneratedAttribute == databaseGeneratedAttributeValue);
            _propertyAssumptions.Add(new DatabaseGeneratedAttributePropertyAssumption(classProperty, assumption, valueField));
        }
 /// <summary>
 /// Creates a property symbol that can be used to describe a property declaration.
 /// </summary>
 public static IPropertySymbol CreatePropertySymbol(IList<AttributeData> attributes, Accessibility accessibility, DeclarationModifiers modifiers, ITypeSymbol type, IPropertySymbol explicitInterfaceSymbol, string name, IList<IParameterSymbol> parameters, IMethodSymbol getMethod, IMethodSymbol setMethod, bool isIndexer = false)
 {
     return CreatePropertySymbol(
         containingType: null,
         attributes: attributes,
         accessibility: accessibility,
         modifiers: modifiers,
         type: type,
         explicitInterfaceSymbol: explicitInterfaceSymbol,
         name: name,
         parameters: parameters,
         getMethod: getMethod,
         setMethod: setMethod,
         isIndexer: isIndexer);
 }
        private List<SimilarityRank<IPropertySymbol>> FindMatches(IPropertySymbol sourceProperty, IEnumerable<IPropertySymbol> targetProperties, IClassPropertyComparer comparer)
        {
            var allMatches = new List<SimilarityRank<IPropertySymbol>>();

            foreach (var targetProperty in targetProperties)
            {
                var rank = comparer.Compare(sourceProperty, targetProperty);
                if (rank.Confidence > 0)
                {
                    allMatches.Add(rank);
                }
            }

            return allMatches;
        }
        private async Task<Solution> ReplacePropertyWithMethodsAsync(
           Document document,
           IPropertySymbol propertySymbol,
           CancellationToken cancellationToken)
        {
            var desiredMethodSuffix = NameGenerator.GenerateUniqueName(propertySymbol.Name,
                n => !HasAnyMatchingGetOrSetMethods(propertySymbol, n));

            var desiredGetMethodName = GetPrefix + desiredMethodSuffix;
            var desiredSetMethodName = SetPrefix + desiredMethodSuffix;

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var originalSolution = document.Project.Solution;
            var propertyReferences = await SymbolFinder.FindReferencesAsync(propertySymbol, originalSolution, cancellationToken).ConfigureAwait(false);

            // Get the warnings we'd like to put at the definition site.
            var definitionWarning = GetDefinitionIssues(propertyReferences);

            var equalityComparer = (IEqualityComparer<IPropertySymbol>)SymbolEquivalenceComparer.Instance;
            var definitionToBackingField = 
                propertyReferences.Select(r => r.Definition)
                                  .OfType<IPropertySymbol>()
                                  .ToDictionary(d => d, GetBackingField, equalityComparer);

            var q = from r in propertyReferences
                    where r.Definition is IPropertySymbol
                    from loc in r.Locations
                    select (property: (IPropertySymbol)r.Definition, location: loc);

            var referencesByDocument = q.ToLookup(t => t.location.Document);

            // References and definitions can overlap (for example, references to one property
            // inside the definition of another).  So we do a multi phase rewrite.  We first
            // rewrite all references to point at the new methods instead.  Then we remove all
            // the actual property definitions and replace them with the new methods.
            var updatedSolution = originalSolution;

            updatedSolution = await UpdateReferencesAsync(
                updatedSolution, referencesByDocument, definitionToBackingField, 
                desiredGetMethodName, desiredSetMethodName, cancellationToken).ConfigureAwait(false);

            updatedSolution = await ReplaceDefinitionsWithMethodsAsync(
                originalSolution, updatedSolution, propertyReferences, definitionToBackingField, 
                desiredGetMethodName, desiredSetMethodName, cancellationToken).ConfigureAwait(false);

            return updatedSolution;
        }
Exemple #23
0
        internal static TypeDeclarationSyntax AddPropertyTo(
            TypeDeclarationSyntax destination,
            IPropertySymbol property,
            CodeGenerationOptions options,
            IList<bool> availableIndices)
        {
            var declaration = GeneratePropertyOrIndexer(property, GetDestination(destination), options);

            // Create a clone of the original type with the new method inserted. 
            var members = Insert(destination.Members, declaration, options,
                availableIndices, after: LastPropertyOrField, before: FirstMember);

            // Find the best place to put the field.  It should go after the last field if we already
            // have fields, or at the beginning of the file if we don't.
            return AddMembersTo(destination, members);
        }
Exemple #24
0
        public static ChangeType CompareTo(this IPropertySymbol symbol, IPropertySymbol comparedTo)
        {
            if (symbol == null)
                return ChangeType.Added;

            if (comparedTo == null)
                return ChangeType.Deleted;

            if (symbol.Type != comparedTo.Type)
                return ChangeType.Rewritten;

            if (symbol.DeclaredAccessibility != comparedTo.DeclaredAccessibility)
                return ChangeType.Rewritten;

            return ChangeType.None;
        }
Exemple #25
0
        private static MemberDeclarationSyntax GenerateIndexerDeclaration(
            IPropertySymbol property,
            CodeGenerationDestination destination,
            CodeGenerationOptions options)
        {
            var explicitInterfaceSpecifier = GenerateExplicitInterfaceSpecifier(property.ExplicitInterfaceImplementations);

            return AddCleanupAnnotationsTo(
                AddAnnotationsTo(property, SyntaxFactory.IndexerDeclaration(
                    attributeLists: AttributeGenerator.GenerateAttributeLists(property.GetAttributes(), options),
                    modifiers: GenerateModifiers(property, destination, options),
                    type: property.Type.GenerateTypeSyntax(),
                    explicitInterfaceSpecifier: explicitInterfaceSpecifier,
                    parameterList: ParameterGenerator.GenerateBracketedParameterList(property.Parameters, explicitInterfaceSpecifier != null, options),
                    accessorList: GenerateAccessorList(property, destination, options))));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="CommonForEachStatementInfo" /> structure.
 /// </summary>
 internal CommonForEachStatementInfo(IMethodSymbol getEnumeratorMethod,
                                     IMethodSymbol moveNextMethod,
                                     IPropertySymbol currentProperty,
                                     IMethodSymbol disposeMethod,
                                     ITypeSymbol elementType,
                                     CommonConversion elementConversion,
                                     CommonConversion currentConversion)
     : this()
 {
     this.GetEnumeratorMethod = getEnumeratorMethod;
     this.MoveNextMethod = moveNextMethod;
     this.CurrentProperty = currentProperty;
     this.DisposeMethod = disposeMethod;
     this.ElementType = elementType;
     this.ElementConversion = elementConversion;
     this.CurrentConversion = currentConversion;
 }
Exemple #27
0
        public static MemberDeclarationSyntax GeneratePropertyOrIndexer(
            IPropertySymbol property,
            CodeGenerationDestination destination,
            CodeGenerationOptions options)
        {
            var reusableSyntax = GetReuseableSyntaxNodeForSymbol<MemberDeclarationSyntax>(property, options);
            if (reusableSyntax != null)
            {
                return reusableSyntax;
            }

            var declaration = property.IsIndexer
                ? GenerateIndexerDeclaration(property, destination, options)
                : GeneratePropertyDeclaration(property, destination, options);

            return ConditionallyAddDocumentationCommentTo(declaration, property, options);
        }
Exemple #28
0
        private SDProperty GetParsedProperty(IPropertySymbol property)
        {
            var sdProperty = new SDProperty(property.GetIdentifier())
            {
                Name = property.Name,
                DeclaringType = _typeRefParser.GetParsedTypeReference(property.ContainingType),
                Accessibility = property.DeclaredAccessibility.ToString().ToLower(),
                ReturnType = _typeRefParser.GetParsedTypeReference(property.Type),
                CanGet = property.GetMethod != null,
                CanSet = property.SetMethod != null,
                IsAbstract = property.IsAbstract,
                IsVirtual = property.IsVirtual,
                IsOverride = property.IsOverride,
                Documentations = DocumentationParser.ParseDocumentation(property)
            };

            ParserOptions.SDRepository.AddMember(sdProperty);
            return sdProperty;
        }
            private IList<SyntaxNode> GetSetAccessorStatements(
                Compilation compilation,
                IPropertySymbol property,
                bool generateAbstractly,
                CancellationToken cancellationToken)
            {
                if (generateAbstractly)
                {
                    return null;
                }

                var factory = this.Document.GetLanguageService<SyntaxGenerator>();
                if (ThroughMember != null)
                {
                    var throughExpression = CreateThroughExpression(factory);
                    SyntaxNode expression;

                    if (property.IsIndexer)
                    {
                        expression = throughExpression;
                    }
                    else
                    {
                        expression = factory.MemberAccessExpression(
                                                throughExpression, factory.IdentifierName(property.Name));
                    }

                    if (property.Parameters.Length > 0)
                    {
                        var arguments = factory.CreateArguments(property.Parameters.As<IParameterSymbol>());
                        expression = factory.ElementAccessExpression(expression, arguments);
                    }

                    expression = factory.AssignmentStatement(expression, factory.IdentifierName("value"));

                    return new[] { factory.ExpressionStatement(expression) };
                }

                return factory.CreateThrowNotImplementedStatementBlock(compilation);
            }
        public static MemberDeclarationSyntax GenerateProperty(PropertyDeclarationSyntax property, IPropertySymbol propertySemanticData, List<string> usedNames)
        {
            PropertyDeclarationSyntax declaration = SF.PropertyDeclaration(property.Type, property.Identifier.Text)
                                    .AddModifiers(property.Modifiers.ToArray());

            var block = SF.Block(GetThrowNotImplementedBlockSyntax());

            if (property.AccessorList.Accessors.Count > 0)
            {
                if (property.AccessorList.Accessors.Any(p => p.Keyword.Text == "get"))
                {
                    declaration = declaration.AddAccessorListAccessors(SF.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration, block));
                }

                if (property.AccessorList.Accessors.Any(p => p.Keyword.Text == "set"))
                {
                    declaration = declaration.AddAccessorListAccessors(SF.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration, block));
                }
            }

            return declaration;
        }
 public abstract SyntaxNode CreatePropertyDeclaration(IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options);
 private ExternalCodeProperty(CodeModelState state, ProjectId projectId, IPropertySymbol symbol)
     : base(state, projectId, symbol)
 {
 }
        internal static async Task TestAddPropertyAsync(
            string initial,
            string expected,
            string name = "P",
            Accessibility defaultAccessibility = Accessibility.Public,
            Accessibility setterAccessibility  = Accessibility.Public,
            DeclarationModifiers modifiers     = default(DeclarationModifiers),
            string getStatements = null,
            string setStatements = null,
            Type type            = null,
            IPropertySymbol explicitInterfaceSymbol = null,
            ImmutableArray <Func <SemanticModel, IParameterSymbol> > parameters = default(ImmutableArray <Func <SemanticModel, IParameterSymbol> >),
            bool isIndexer = false,
            CodeGenerationOptions codeGenerationOptions = default(CodeGenerationOptions),
            bool ignoreTrivia = true,
            IDictionary <OptionKey, object> options = null)
        {
            // This assumes that tests will not use place holders for get/set statements at the same time
            if (getStatements != null)
            {
                expected = expected.Replace("$$", getStatements);
            }

            if (setStatements != null)
            {
                expected = expected.Replace("$$", setStatements);
            }

            using (var context = await TestContext.CreateAsync(initial, expected, ignoreTrivia))
            {
                if (options != null)
                {
                    foreach (var kvp in options)
                    {
                        context.Workspace.Options = context.Workspace.Options.WithChangedOption(kvp.Key, kvp.Value);
                    }
                }

                var typeSymbol          = GetTypeSymbol(type)(context.SemanticModel);
                var getParameterSymbols = GetParameterSymbols(parameters, context);
                var setParameterSymbols = getParameterSymbols == null
                    ? default(ImmutableArray <IParameterSymbol>)
                    : getParameterSymbols.Add(Parameter(type, "value")(context.SemanticModel));
                IMethodSymbol getAccessor = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    default(ImmutableArray <AttributeData>),
                    defaultAccessibility,
                    new DeclarationModifiers(isAbstract: getStatements == null),
                    typeSymbol,
                    false,
                    null,
                    "get_" + name,
                    default(ImmutableArray <ITypeParameterSymbol>),
                    getParameterSymbols,
                    statements: context.ParseStatements(getStatements));
                IMethodSymbol setAccessor = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    default(ImmutableArray <AttributeData>),
                    setterAccessibility,
                    new DeclarationModifiers(isAbstract: setStatements == null),
                    GetTypeSymbol(typeof(void))(context.SemanticModel),
                    false,
                    null,
                    "set_" + name,
                    default(ImmutableArray <ITypeParameterSymbol>),
                    setParameterSymbols,
                    statements: context.ParseStatements(setStatements));

                // If get is provided but set isn't, we don't want an accessor for set
                if (getStatements != null && setStatements == null)
                {
                    setAccessor = null;
                }

                // If set is provided but get isn't, we don't want an accessor for get
                if (getStatements == null && setStatements != null)
                {
                    getAccessor = null;
                }

                var property = CodeGenerationSymbolFactory.CreatePropertySymbol(
                    default(ImmutableArray <AttributeData>),
                    defaultAccessibility,
                    modifiers,
                    typeSymbol,
                    false,
                    explicitInterfaceSymbol,
                    name,
                    getParameterSymbols,
                    getAccessor,
                    setAccessor,
                    isIndexer);
                context.Result = await context.Service.AddPropertyAsync(context.Solution, (INamedTypeSymbol)context.GetDestination(), property, codeGenerationOptions);
            }
        }
Exemple #34
0
 public static bool IsInstanceLengthCheck(
     IPropertySymbol lengthLikeProperty,
     IOperation instance,
     IOperation operation
     ) =>
 operation is IPropertyReferenceOperation propertyRef &&
 protected void AddDescriptionForProperty(IPropertySymbol symbol)
 {
     AddToGroup(SymbolDescriptionGroups.MainDescription,
                ToMinimalDisplayParts(symbol, s_memberSignatureDisplayFormat));
 }
Exemple #36
0
        private async Task <TestGenerationContext> CollectTestGenerationContextAsync(
            ProjectItemSummary selectedFile,
            string targetProjectNamespace,
            TestFramework testFramework,
            MockFramework mockFramework)
        {
            Microsoft.CodeAnalysis.Solution solution = CreateUnitTestBoilerplateCommandPackage.VisualStudioWorkspace.CurrentSolution;
            DocumentId documentId = solution.GetDocumentIdsWithFilePath(selectedFile.FilePath).FirstOrDefault();

            if (documentId == null)
            {
                throw new InvalidOperationException("Could not find document in solution with file path " + selectedFile.FilePath);
            }

            var document = solution.GetDocument(documentId);

            SyntaxNode root = await document.GetSyntaxRootAsync();

            SemanticModel semanticModel = await document.GetSemanticModelAsync();

            SyntaxNode firstClassDeclaration = root.DescendantNodes().FirstOrDefault(node => node.Kind() == SyntaxKind.ClassDeclaration);

            if (firstClassDeclaration == null)
            {
                throw new InvalidOperationException("Could not find class declaration.");
            }

            if (firstClassDeclaration.ChildTokens().Any(node => node.Kind() == SyntaxKind.AbstractKeyword))
            {
                throw new InvalidOperationException("Cannot unit test an abstract class.");
            }

            SyntaxToken classIdentifierToken = firstClassDeclaration.ChildTokens().FirstOrDefault(n => n.Kind() == SyntaxKind.IdentifierToken);

            if (classIdentifierToken == default(SyntaxToken))
            {
                throw new InvalidOperationException("Could not find class identifier.");
            }

            NamespaceDeclarationSyntax namespaceDeclarationSyntax = null;

            if (!TypeUtilities.TryGetParentSyntax(firstClassDeclaration, out namespaceDeclarationSyntax))
            {
                throw new InvalidOperationException("Could not find class namespace.");
            }

            // Find property injection types
            var injectableProperties = new List <InjectableProperty>();

            string           classFullName = namespaceDeclarationSyntax.Name + "." + classIdentifierToken;
            INamedTypeSymbol classType     = semanticModel.Compilation.GetTypeByMetadataName(classFullName);

            foreach (ISymbol member in classType.GetBaseTypesAndThis().SelectMany(n => n.GetMembers()))
            {
                if (member.Kind == SymbolKind.Property)
                {
                    IPropertySymbol property = (IPropertySymbol)member;

                    foreach (AttributeData attribute in property.GetAttributes())
                    {
                        if (PropertyInjectionAttributeNames.Contains(attribute.AttributeClass.ToString()))
                        {
                            var injectableProperty = InjectableProperty.TryCreateInjectableProperty(property.Name, property.Type.ToString(), mockFramework);
                            if (injectableProperty != null)
                            {
                                injectableProperties.Add(injectableProperty);
                            }
                        }
                    }
                }
            }

            string className = classIdentifierToken.ToString();

            // Find constructor injection types
            List <InjectableType> constructorInjectionTypes = new List <InjectableType>();

            SyntaxNode constructorDeclaration = firstClassDeclaration.ChildNodes().FirstOrDefault(n => n.Kind() == SyntaxKind.ConstructorDeclaration);

            if (constructorDeclaration != null)
            {
                constructorInjectionTypes.AddRange(
                    GetParameterListNodes(constructorDeclaration)
                    .Select(node => InjectableType.TryCreateInjectableTypeFromParameterNode(node, semanticModel, mockFramework)));
            }

            // Find public method declarations
            IList <MethodDescriptor> methodDeclarations = new List <MethodDescriptor>();

            foreach (MethodDeclarationSyntax methodDeclaration in
                     firstClassDeclaration.ChildNodes().Where(
                         n => n.Kind() == SyntaxKind.MethodDeclaration &&
                         ((MethodDeclarationSyntax)n).Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword))))
            {
                var parameterList = GetParameterListNodes(methodDeclaration).ToList();

                var parameterTypes = GetArgumentDescriptors(parameterList, semanticModel, mockFramework);

                var isAsync =
                    methodDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)) ||
                    DoesReturnTask(methodDeclaration);

                var hasReturnType = !DoesReturnNonGenericTask(methodDeclaration) && !DoesReturnVoid(methodDeclaration);

                methodDeclarations.Add(new MethodDescriptor(methodDeclaration.Identifier.Text, parameterTypes, isAsync, hasReturnType));
            }

            string unitTestNamespace;

            string relativePath = this.GetRelativePath(selectedFile);

            if (string.IsNullOrEmpty(relativePath))
            {
                unitTestNamespace = targetProjectNamespace;
            }
            else
            {
                List <string> defaultNamespaceParts  = targetProjectNamespace.Split('.').ToList();
                List <string> unitTestNamespaceParts = new List <string>(defaultNamespaceParts);
                unitTestNamespaceParts.AddRange(relativePath.Split('\\'));

                unitTestNamespace = string.Join(".", unitTestNamespaceParts);
            }

            List <InjectableType> injectedTypes = new List <InjectableType>(injectableProperties);

            injectedTypes.AddRange(constructorInjectionTypes.Where(t => t != null));

            GenerateMockNames(injectedTypes);

            return(new TestGenerationContext(
                       mockFramework,
                       testFramework,
                       unitTestNamespace,
                       className,
                       namespaceDeclarationSyntax.Name.ToString(),
                       injectableProperties,
                       constructorInjectionTypes,
                       injectedTypes,
                       methodDeclarations));
        }
 private IList <SymbolDisplayPart> GetPostambleParts(IPropertySymbol indexer)
 {
     return(SpecializedCollections.SingletonList(
                Punctuation(SyntaxKind.CloseBracketToken)));
 }
Exemple #38
0
            private bool IsAssigningIntendedValueToPropertyDerivedFromType(SyntaxNode assignment,
                                                                           SemanticModel model,
                                                                           Func <IPropertySymbol, bool> isTargetPropertyFunc,
                                                                           Func <SyntaxNode, bool> isIntendedValueFunc,
                                                                           out bool isTargetProperty)
            {
                bool isIntendedValue;

                SyntaxNode left  = _syntaxNodeHelper.GetAssignmentLeftNode(assignment);
                SyntaxNode right = _syntaxNodeHelper.GetAssignmentRightNode(assignment);

                IPropertySymbol leftSymbol = SyntaxNodeHelper.GetCalleePropertySymbol(left, model);

                isTargetProperty = isTargetPropertyFunc(leftSymbol);

                if (!isTargetProperty)
                {
                    return(false);
                }

                // call to isIntendedValueFunc must be after checking isTargetProperty
                // since the logic of isIntendedValueFunc relies on corresponding SyntaxNode
                isIntendedValue = isIntendedValueFunc(right);

                // Here's an example that needs some extra check:
                //
                //    class TestClass : XmlDocument
                //    {
                //        private XmlDocument doc = new XmlDocument();
                //        public TestClass(XmlDocument doc)
                //        {
                //            this.doc.XmlResolver = null;
                //        }
                //    }
                //
                // Even though the assignment would return true for both isTargetPropertyFunc and isIntendedValueFunc,
                // it is not setting the actual property for this class.

                // The goal is to find all assignment like in the example above, "this.xxx.xxx.Property = ...;".
                // For simplicity, here we adopt a simple but inaccurate logic:
                //   If the target is a member access node, then the only pattern we are looking for is "this.Property"
                SyntaxNode memberAccessNode = _syntaxNodeHelper.GetDescendantMemberAccessExpressionNodes(left).FirstOrDefault();

                // if assignment target doesn't have any member access node,
                // then we treat it as an instance property access without explicit 'this' ('Me' in VB)
                if (memberAccessNode == null)
                {
                    //stop here, to avoid false positive, as long as there's one setting <Property> to secure value, we are happy
                    return(isIntendedValue);
                }

                SyntaxNode exp       = _syntaxNodeHelper.GetMemberAccessExpressionNode(memberAccessNode);
                ISymbol    expSymbol = SyntaxNodeHelper.GetSymbol(exp, model);

                isTargetProperty = expSymbol.Kind == SymbolKind.Parameter && ((IParameterSymbol)expSymbol).IsThis;
                if (!isTargetProperty)
                {
                    return(false);
                }

                SyntaxNode name       = _syntaxNodeHelper.GetMemberAccessNameNode(memberAccessNode);
                ISymbol    nameSymbol = SyntaxNodeHelper.GetSymbol(name, model);

                isTargetProperty = isTargetPropertyFunc(nameSymbol as IPropertySymbol);
                if (!isTargetProperty)
                {
                    return(false);
                }

                // stop here, same reason as stated above
                return(isIntendedValue);
            }
        private static bool IsAbstractPropertyImplemented(INamedTypeSymbol classOrStructType, IPropertySymbol propertySymbol, CancellationToken cancellationToken)
        {
            // A property is only fully implemented if both it's setter and getter is implemented.
            if (propertySymbol.GetMethod != null)
            {
                if (classOrStructType.FindImplementationForAbstractMember(propertySymbol.GetMethod) == null)
                {
                    return(false);
                }
            }

            if (propertySymbol.SetMethod != null)
            {
                if (classOrStructType.FindImplementationForAbstractMember(propertySymbol.SetMethod) == null)
                {
                    return(false);
                }
            }

            return(true);
        }
Exemple #40
0
 internal static bool TryGetProperty(this ITypeSymbol type, string name, out IPropertySymbol property)
 {
     return(type.TryGetSingleMember(name, out property));
 }
Exemple #41
0
 protected override IEnumerable <Diagnostic> AnalyzeName(IPropertySymbol symbol) => AnalyzeName(symbol);
Exemple #42
0
 protected override bool ShallAnalyze(IPropertySymbol symbol) => ShallAnalyze(symbol.Type) && symbol.ContainingType.IsTestClass() is false;
 public override SyntaxNode CreatePropertyDeclaration(
     IPropertySymbol property, CodeGenerationDestination destination, CodeGenerationOptions options)
 {
     return(PropertyGenerator.GeneratePropertyDeclaration(property, destination, options));
 }
Exemple #44
0
 protected abstract bool TryInitializeExplicitInterfaceState(SemanticDocument document, SyntaxNode node, CancellationToken cancellationToken, out SyntaxToken identifierToken, out IPropertySymbol propertySymbol, out INamedTypeSymbol typeToGenerateIn);
        public static void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context)
        {
            var property = (PropertyDeclarationSyntax)context.Node;

            if (property.ContainsDiagnostics)
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IFieldSymbol fieldSymbol = null;

            AccessorDeclarationSyntax getter = null;
            AccessorDeclarationSyntax setter = null;

            ArrowExpressionClauseSyntax expressionBody = property.ExpressionBody;

            if (expressionBody != null)
            {
                fieldSymbol = GetBackingFieldSymbol(expressionBody, semanticModel, cancellationToken);
            }
            else
            {
                getter = property.Getter();

                if (getter != null)
                {
                    setter = property.Setter();

                    if (setter != null)
                    {
                        fieldSymbol = GetBackingFieldSymbol(getter, setter, semanticModel, cancellationToken);
                    }
                    else
                    {
                        fieldSymbol = GetBackingFieldSymbol(getter, semanticModel, cancellationToken);
                    }
                }
            }

            if (fieldSymbol == null)
            {
                return;
            }

            var variableDeclarator = (VariableDeclaratorSyntax)fieldSymbol.GetSyntax(cancellationToken);

            if (variableDeclarator.SyntaxTree != property.SyntaxTree)
            {
                return;
            }

            IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(property, cancellationToken);

            if (propertySymbol == null)
            {
                return;
            }

            if (!propertySymbol.ExplicitInterfaceImplementations.IsDefaultOrEmpty)
            {
                return;
            }

            if (propertySymbol.IsStatic != fieldSymbol.IsStatic)
            {
                return;
            }

            if (!propertySymbol.Type.Equals(fieldSymbol.Type))
            {
                return;
            }

            if (propertySymbol.ContainingType?.Equals(fieldSymbol.ContainingType) != true)
            {
                return;
            }

            if (setter == null &&
                propertySymbol.IsOverride &&
                propertySymbol.OverriddenProperty?.SetMethod != null)
            {
                return;
            }

            if (BackingFieldHasNonSerializedAttribute(fieldSymbol, context.Compilation))
            {
                return;
            }

            if (HasStructLayoutAttributeWithExplicitKind(propertySymbol.ContainingType, context.Compilation))
            {
                return;
            }

            if (IsBackingFieldUsedInRefOrOutArgument(context, fieldSymbol, property))
            {
                return;
            }

            if (!CheckPreprocessorDirectives(property, variableDeclarator))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.UseAutoProperty, property.Identifier);

            if (property.ExpressionBody != null)
            {
                context.ReportNode(DiagnosticDescriptors.UseAutoPropertyFadeOut, property.ExpressionBody);
            }
            else
            {
                if (getter != null)
                {
                    FadeOutBodyOrExpressionBody(context, getter);
                }

                if (setter != null)
                {
                    FadeOutBodyOrExpressionBody(context, setter);
                }
            }
        }
 private bool HasAnyMatchingGetOrSetMethods(IPropertySymbol property, string name)
 {
     return(HasAnyMatchingGetMethods(property, name) ||
            HasAnyMatchingSetMethods(property, name));
 }
        public static IPropertySymbol OverrideProperty(
            this SyntaxGenerator codeFactory,
            IPropertySymbol overriddenProperty,
            SymbolModifiers modifiers,
            INamedTypeSymbol containingType,
            Document document,
            CancellationToken cancellationToken)
        {
            var getAccessibility = overriddenProperty.GetMethod.ComputeResultantAccessibility(containingType);
            var setAccessibility = overriddenProperty.SetMethod.ComputeResultantAccessibility(containingType);

            SyntaxNode getBody = null;
            SyntaxNode setBody = null;

            // Implement an abstract property by throwing not implemented in accessors.
            if (overriddenProperty.IsAbstract)
            {
                getBody = codeFactory.CreateThrowNotImplementStatement(document.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult(cancellationToken));
                setBody = getBody;
            }
            else if (overriddenProperty.IsIndexer() && document.Project.Language == LanguageNames.CSharp)
            {
                // Indexer: return or set base[]. Only in C#, since VB must refer to these by name.
                getBody = codeFactory.ReturnStatement(
                    codeFactory.ElementAccessExpression(
                        codeFactory.BaseExpression(),
                        codeFactory.CreateArguments(overriddenProperty.Parameters)));

                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                        codeFactory.ElementAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.CreateArguments(overriddenProperty.Parameters)),
                        codeFactory.IdentifierName("value")));
            }
            else if (overriddenProperty.GetParameters().Any())
            {
                // Call accessors directly if C# overriding VB
                if (document.Project.Language == LanguageNames.CSharp &&
                    SymbolFinder.FindSourceDefinitionAsync(overriddenProperty, document.Project.Solution)
                    .WaitAndGetResult(CancellationToken.None).Language == LanguageNames.VisualBasic)
                {
                    var getName = overriddenProperty.GetMethod != null ? overriddenProperty.GetMethod.Name : null;
                    var setName = overriddenProperty.SetMethod != null ? overriddenProperty.SetMethod.Name : null;

                    getBody = getName == null
                        ? null
                        : codeFactory.ReturnStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(getName)),
                            codeFactory.CreateArguments(overriddenProperty.Parameters)));

                    setBody = setName == null
                        ? null
                        : codeFactory.ExpressionStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(setName)),
                            codeFactory.CreateArguments(overriddenProperty.SetMethod.GetParameters())));
                }
                else
                {
                    getBody = codeFactory.ReturnStatement(
                        codeFactory.InvocationExpression(
                            codeFactory.MemberAccessExpression(
                                codeFactory.BaseExpression(),
                                codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters)));
                    setBody = codeFactory.ExpressionStatement(
                        codeFactory.AssignmentStatement(
                            codeFactory.InvocationExpression(
                                codeFactory.MemberAccessExpression(
                                    codeFactory.BaseExpression(),
                                    codeFactory.IdentifierName(overriddenProperty.Name)), codeFactory.CreateArguments(overriddenProperty.Parameters)),
                            codeFactory.IdentifierName("value")));
                }
            }
            else
            {
                // Regular property: return or set the base property
                getBody = codeFactory.ReturnStatement(
                    codeFactory.MemberAccessExpression(
                        codeFactory.BaseExpression(),
                        codeFactory.IdentifierName(overriddenProperty.Name)));
                setBody = codeFactory.ExpressionStatement(
                    codeFactory.AssignmentStatement(
                        codeFactory.MemberAccessExpression(
                            codeFactory.BaseExpression(),
                            codeFactory.IdentifierName(overriddenProperty.Name)),
                        codeFactory.IdentifierName("value")));
            }

            // Only generate a getter if the base getter is accessible.
            IMethodSymbol accessorGet = null;

            if (overriddenProperty.GetMethod != null && overriddenProperty.GetMethod.IsAccessibleWithin(containingType))
            {
                accessorGet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.GetMethod,
                    accessibility: getAccessibility,
                    statements: new[] { getBody },
                    modifiers: modifiers);
            }

            // Only generate a setter if the base setter is accessible.
            IMethodSymbol accessorSet = null;

            if (overriddenProperty.SetMethod != null &&
                overriddenProperty.SetMethod.IsAccessibleWithin(containingType) &&
                overriddenProperty.SetMethod.DeclaredAccessibility != Accessibility.Private)
            {
                accessorSet = CodeGenerationSymbolFactory.CreateMethodSymbol(
                    overriddenProperty.SetMethod,
                    accessibility: setAccessibility,
                    statements: new[] { setBody },
                    modifiers: modifiers);
            }

            return(CodeGenerationSymbolFactory.CreatePropertySymbol(
                       overriddenProperty,
                       accessibility: overriddenProperty.ComputeResultantAccessibility(containingType),
                       modifiers: modifiers,
                       name: overriddenProperty.Name,
                       isIndexer: overriddenProperty.IsIndexer(),
                       getMethod: accessorGet,
                       setMethod: accessorSet));
        }
Exemple #48
0
 public PropertyDescription(uint fieldId, IPropertySymbol property)
 {
     this.FieldId  = fieldId;
     this.Property = property;
 }
Exemple #49
0
 private static bool HasPublicSetter(IPropertySymbol propertySymbol) =>
 propertySymbol.SetMethod != null &&
 !privateOrInternalAccessibility.Contains(propertySymbol.GetEffectiveAccessibility()) &&
 !privateOrInternalAccessibility.Contains(propertySymbol.SetMethod.DeclaredAccessibility);
 protected abstract bool ImplementsExplicitGetterOrSetter(IPropertySymbol property);
 private static int CompareProperties(IPropertySymbol xProperty, string[] xTypeNames, IPropertySymbol yProperty, string[] yTypeNames)
 {
     return(CompareParameters(xProperty.Parameters, xTypeNames, yProperty.Parameters, yTypeNames));
 }
 protected abstract IEnumerable <FieldData> FindFieldReads(IPropertySymbol property, Compilation compilation);
Exemple #53
0
        public static PropertyValidationResult GetPropertyRetrieverArgumentStatus(
            ArgumentSyntax propertyRetrieverArgument,
            SyntaxNodeAnalysisContext context,
            ITypeSymbol propertyValueTypeIfKnown,
            bool allowReadOnlyProperties,
            out IPropertySymbol propertyIfSuccessfullyRetrieved)
        {
            if (propertyRetrieverArgument == null)
            {
                throw new ArgumentNullException(nameof(propertyRetrieverArgument));
            }

            // Most of the validation here ensures that an argument is passed is an explicit property getter lamba (eg. "_ => _.Name") but there
            // are times where it would be helpful to be able to share a lambda reference (or pass one into a method that will then pass it to a
            // With call) and so we don't want to ONLY support the explicit lambda formats. To enable that, there is a PropertyIdentifier<T, TProp>
            // class that may be cast to a Func<T, TProp> which means that the lambda validation need not apply (note that the lambda validation
            // WILL be applied to the PropertyIdentifier<T, TProp> initialisations, so validation may not be bypassed in this manner - it's just
            // moved around a bit)
            // - Note: We don't have to worry about propertyValueTypeIfKnown here because the validation around ensuring that we don't use too
            //   loose of a type will have been done when the PropertyIdentifier<T, TPropertyValue> was initialised
            if (IsPropertyIdentifierReference(propertyRetrieverArgument.Expression, context))
            {
                propertyIfSuccessfullyRetrieved = null;
                return(PropertyValidationResult.Ok);
            }

            // An alternative to generating and passing round PropertyIdentifier<T, TPropertyValue> references is to mark method arguments that are
            // of the the appropriate lambda forms with the [PropertyIdentifier] attribute - then the parameter may be passed into a With or CtorSet
            // method (since there will have been validation elsewhere to ensure that the argument passed to [PropertyIdentifier] parameter meets
            // the criteria checked for below)
            // - Note: We don't have to worry about propertyValueTypeIfKnown for the same reason as we don't above; the validation will have been
            //   applied at the point at which the [PropertyIdentifier] argument was provided
            bool isNotPropertyIdentifierButIsMethodParameterOfDelegateType;

            if (IsPropertyIdentifierArgument(propertyRetrieverArgument.Expression, context, out isNotPropertyIdentifierButIsMethodParameterOfDelegateType))
            {
                propertyIfSuccessfullyRetrieved = null;
                return(PropertyValidationResult.Ok);
            }
            else if (isNotPropertyIdentifierButIsMethodParameterOfDelegateType)
            {
                // If it the property identifier is a method argument value and it's a delegate but it doesn't have the [PropertyIdentifier] attribute
                // on it then it seems likely that the user has just forgotten it (or is not aware of it) so, instead of showing the more generic
                // NotSimpleLambdaExpression warning, allow the analyser to show a more helpful message.
                propertyIfSuccessfullyRetrieved = null;
                return(PropertyValidationResult.MethodParameterWithoutPropertyIdentifierAttribute);
            }

            SimpleNameSyntax targetNameIfSimpleLambdaExpression;

            if (propertyRetrieverArgument.Expression.Kind() != SyntaxKind.SimpleLambdaExpression)
            {
                propertyIfSuccessfullyRetrieved = null;
                return(PropertyValidationResult.NotSimpleLambdaExpression);
            }
            else
            {
                var propertyRetrieverExpression = (SimpleLambdaExpressionSyntax)propertyRetrieverArgument.Expression;
                if (propertyRetrieverExpression.Body.Kind() != SyntaxKind.SimpleMemberAccessExpression)
                {
                    propertyIfSuccessfullyRetrieved = null;
                    return(PropertyValidationResult.NotSimpleLambdaExpression);
                }

                var memberAccess = (MemberAccessExpressionSyntax)propertyRetrieverExpression.Body;
                if (memberAccess.Expression.Kind() != SyntaxKind.IdentifierName)
                {
                    // The lambda must be of the form "_ => _.Name" and not "_ => ((ISomething)_).Name" or anything like that. This ensures
                    // that all public gettable properties on the type can be checked for a setter while also allowing it to implement other
                    // interfaces which don't follow these rules, so long as those interfaces are explicitly implemented. If it was acceptable
                    // to cast the lambda target then this would not be possible.
                    propertyIfSuccessfullyRetrieved = null;
                    return(PropertyValidationResult.IndirectTargetAccess);
                }

                targetNameIfSimpleLambdaExpression = ((MemberAccessExpressionSyntax)propertyRetrieverExpression.Body).Name;
            }

            var target = context.SemanticModel.GetSymbolInfo(targetNameIfSimpleLambdaExpression).Symbol;

            if (target == null)
            {
                // We won't be able to retrieve a Symbol "if the given expression did not bind successfully to a single symbol" - this means
                // that the code is not in a complete state. We can only identify errors when everything is properly written and consistent.
                {
                    propertyIfSuccessfullyRetrieved = null;
                    return(PropertyValidationResult.UnableToConfirmOrDeny);
                }
            }

            propertyIfSuccessfullyRetrieved = target as IPropertySymbol;
            if (propertyIfSuccessfullyRetrieved == null)
            {
                return(PropertyValidationResult.LambdaDoesNotTargetProperty);
            }

            if (propertyIfSuccessfullyRetrieved.GetMethod == null)
            {
                return(PropertyValidationResult.MissingGetter);
            }
            if (HasDisallowedAttribute(propertyIfSuccessfullyRetrieved.GetMethod))
            {
                return(PropertyValidationResult.GetterHasBridgeAttributes);
            }

            var hasReadOnlyAttribute = propertyIfSuccessfullyRetrieved.GetAttributes().Any(
                a => a.AttributeClass.ToString() == AnalyserAssemblyName + ".ReadOnlyAttribute"
                );

            if (!allowReadOnlyProperties && hasReadOnlyAttribute)
            {
                return(PropertyValidationResult.IsReadOnly);
            }

            // Note about looking for a setter: Previously, it was required that a property have a getter AND a setter, though it was fine for
            // that setter to be private (in fact, it SHOULD be private if the containing class is not to have modifiable instances). This check
            // had to be relaxed for properties in classes in referenced assemblies since the meta data for the external assembly would not declare
            // the presence of a private setter. Now that (as of September 2016) Bridge supports C# 6 syntax, we also have to deal with the case
            // where a setter may not be present in classes that we have access to the source code for at this point. We COULD do extra work to
            // try to ensure that this only happens if the getter has no body (meaning that it must be a readonly auto-property, if it has a
            // getter with no body and has no setter) but I think that it makes more sense to just skip the check altogether - it's skipped for
            // referenced assemblies because the assumption is that the IAmImmutable analyser would pick up any invalid classes in the project
            // project in which those classes were written, so we can do the same here (yes, someone could bypass that by disabling the analyser
            // or using Visual Studio pre-2015 or one of any number of other means) but there are lots of ways to get around the type system if
            // you're creative when considering a Bridge project since JavaScript is so malleable (so it doesn't seem worth going mad trying to
            // make it impossible to circumvent, it's fine just to make it so that there's clearly some shenanigans going on and that everything
            // will work if there isn't).
            if ((propertyIfSuccessfullyRetrieved.SetMethod != null) && HasDisallowedAttribute(propertyIfSuccessfullyRetrieved.SetMethod))
            {
                return(PropertyValidationResult.SetterHasBridgeAttributes);
            }

            // Ensure that the property value is at least as specific a type as the target property. For example, if the target property is of
            // type string and we know that the value that the code wants to set that property to be is an object then we need to nip that in
            // the bud. This is, unfortunately, quite an easy situation to fall into - if, for example, "x" is an instance of an IAmImmutable-
            // implementing class that has a "Name" property that is a string then the following will compile
            //
            //   x = x.With(_ => _.Name, new object());
            //
            // Although the lambda "_ => _.Name" is a Func<Whatever, string> it may also be interpreted as a Func<Whatever, object> if the
            // "TPropertyValue" generic type argument of the With<T, TPropertyValue> is inferred (or explicitly specified) as object.
            if ((propertyValueTypeIfKnown != null) && !(propertyValueTypeIfKnown is IErrorTypeSymbol))
            {
                if (!IsEqualToOrInheritsFrom(propertyValueTypeIfKnown, propertyIfSuccessfullyRetrieved.GetMethod.ReturnType))
                {
                    return(PropertyValidationResult.PropertyIsOfMoreSpecificTypeThanSpecificValueType);
                }
            }
            return(PropertyValidationResult.Ok);
        }
Exemple #54
0
 protected bool IsAutoProperty(IPropertySymbol property)
 {
     return(IsAutoProperty(property, out _));
 }
Exemple #55
0
 protected abstract void BuildPropertyDeclaration(IPropertySymbol propertySymbol, _VSOBJDESCOPTIONS options);
 public static ExpressionSyntax CreateNewExpression(SyntaxNode node, SyntaxToken identifier, IPropertySymbol propertySymbol)
 {
     if (node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) &&
         ((MemberAccessExpressionSyntax)node.Parent).Name == node)
     {
         return(IdentifierName(identifier));
     }
     else if (propertySymbol.IsStatic)
     {
         return(ParseName($"{propertySymbol.ContainingType.ToTypeSyntax()}.{propertySymbol.ToDisplayString(_symbolDisplayFormat)}")
                .WithSimplifierAnnotation());
     }
     else
     {
         return(IdentifierName(identifier).QualifyWithThis());
     }
 }
        internal static EnvDTE.CodeProperty Create(CodeModelState state, ProjectId projectId, IPropertySymbol symbol)
        {
            var element = new ExternalCodeProperty(state, projectId, symbol);

            return((EnvDTE.CodeProperty)ComAggregate.CreateAggregatedObject(element));
        }
        public static async Task <Solution> RefactorAsync(
            Document document,
            PropertyDeclarationSyntax propertyDeclaration,
            CancellationToken cancellationToken)
        {
            SyntaxToken propertyIdentifier = propertyDeclaration.Identifier.WithoutTrivia();

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, cancellationToken);

            ISymbol fieldSymbol = GetFieldSymbol(propertyDeclaration, semanticModel, cancellationToken);

            var variableDeclarator = (VariableDeclaratorSyntax)await fieldSymbol.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken).ConfigureAwait(false);

            var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent;

            var fieldDeclaration = (FieldDeclarationSyntax)variableDeclaration.Parent;

            bool isSingleDeclarator = variableDeclaration.Variables.Count == 1;

            Solution solution = document.Solution();

            foreach (DocumentReferenceInfo info in await SyntaxFinder.FindReferencesByDocumentAsync(fieldSymbol, solution, allowCandidate: false, cancellationToken: cancellationToken).ConfigureAwait(false))
            {
                ImmutableArray <SyntaxNode> nodes = info.References;

                if (propertyDeclaration.SyntaxTree == info.SyntaxTree)
                {
                    nodes = nodes.Add(propertyDeclaration);

                    if (isSingleDeclarator)
                    {
                        nodes = nodes.Add(fieldDeclaration);
                    }
                    else
                    {
                        nodes = nodes.Add(variableDeclarator);
                    }
                }

                SyntaxNode newRoot = info.Root.ReplaceNodes(nodes, (node, _) =>
                {
                    switch (node.Kind())
                    {
                    case SyntaxKind.IdentifierName:
                        {
                            return(CreateNewExpression(node, propertyIdentifier, propertySymbol)
                                   .WithTriviaFrom(node)
                                   .WithFormatterAnnotation());
                        }

                    case SyntaxKind.PropertyDeclaration:
                        {
                            return(CreateAutoProperty(propertyDeclaration, variableDeclarator.Initializer));
                        }

                    case SyntaxKind.VariableDeclarator:
                    case SyntaxKind.FieldDeclaration:
                        {
                            return(node.WithAdditionalAnnotations(_removeAnnotation));
                        }

                    default:
                        {
                            Debug.Fail(node.ToString());
                            return(node);
                        }
                    }
                });

                SyntaxNode nodeToRemove = newRoot.GetAnnotatedNodes(_removeAnnotation).FirstOrDefault();

                if (nodeToRemove != null)
                {
                    newRoot = newRoot.RemoveNode(nodeToRemove, SyntaxRemoveOptions.KeepUnbalancedDirectives);
                }

                solution = solution.WithDocumentSyntaxRoot(info.Document.Id, newRoot);
            }

            return(solution);
        }
Exemple #59
0
 public static bool?AreAutoPropertiesMinimized(this IPropertySymbol property)
 {
     return(property.GetAttributeValue <bool?>(Context.Instance.JsAttributeType, "AreAutoPropertiesMinimized", null));
 }
        protected override TDeclarationNode AddProperty <TDeclarationNode>(TDeclarationNode destination, IPropertySymbol property, CodeGenerationOptions options, IList <bool> availableIndices)
        {
            CheckDeclarationNode <TypeDeclarationSyntax, CompilationUnitSyntax>(destination);

            // Can't generate a property with parameters.  So generate the setter/getter individually.
            if (!PropertyGenerator.CanBeGenerated(property))
            {
                var members = new List <ISymbol>();
                if (property.GetMethod != null)
                {
                    var getMethod = property.GetMethod;

                    if (property is CodeGenerationSymbol)
                    {
                        foreach (var annotation in ((CodeGenerationSymbol)property).GetAnnotations())
                        {
                            getMethod = annotation.AddAnnotationToSymbol(getMethod);
                        }
                    }

                    members.Add(getMethod);
                }

                if (property.SetMethod != null)
                {
                    var setMethod = property.SetMethod;

                    if (property is CodeGenerationSymbol)
                    {
                        foreach (var annotation in ((CodeGenerationSymbol)property).GetAnnotations())
                        {
                            setMethod = annotation.AddAnnotationToSymbol(setMethod);
                        }
                    }

                    members.Add(setMethod);
                }

                if (members.Count > 1)
                {
                    options = CreateOptionsForMultipleMembers(options);
                }

                return(AddMembers(destination, members, availableIndices, options));
            }

            if (destination is TypeDeclarationSyntax)
            {
                return(Cast <TDeclarationNode>(PropertyGenerator.AddPropertyTo(Cast <TypeDeclarationSyntax>(destination), property, options, availableIndices)));
            }
            else
            {
                return(Cast <TDeclarationNode>(PropertyGenerator.AddPropertyTo(Cast <CompilationUnitSyntax>(destination), property, options, availableIndices)));
            }
        }