public override void Initialize(AnalysisContext analysisContext) { analysisContext.EnableConcurrentExecution(); analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); analysisContext.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation); compilationContext.RegisterOperationBlockActionInternal(context => { var method = context.OwningSymbol as IMethodSymbol; if (method == null) { return; } if (!method.IsFinalizer()) { return; } if (IsEmptyFinalizer(context.OperationBlocks, conditionalAttributeSymbol)) { context.ReportDiagnostic(context.OwningSymbol.CreateDiagnostic(Rule)); } }); }); }
private static bool IsConditionalInvocation(InvocationExpressionSyntax invocationExpr, SemanticModel semanticModel) { if (!(semanticModel.GetSymbolInfo(invocationExpr).Symbol is IMethodSymbol invocationSymbol)) { // Presumably, if the user has typed something but it doesn't have a symbol yet, the body won't be empty // once all compile errors are corrected, so we return false here. return(false); } var conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(semanticModel.Compilation); return(InvocationIsConditional(invocationSymbol, conditionalAttributeSymbol)); }
protected override bool IsEmptyFinalizer(SyntaxNode methodBody, CodeBlockAnalysisContext analysisContext) { var destructorDeclaration = (DestructorDeclarationSyntax)methodBody; if ((destructorDeclaration?.Body?.Statements.Count ?? 0) == 0) { return(true); } if (destructorDeclaration.Body.Statements.Count == 1) { var body = destructorDeclaration.Body.Statements[0]; if (body.Kind() == CodeAnalysis.CSharp.SyntaxKind.ThrowStatement) { return(true); } if (body.Kind() == CodeAnalysis.CSharp.SyntaxKind.ExpressionStatement && body is ExpressionStatementSyntax expr && expr.Expression.Kind() == CodeAnalysis.CSharp.SyntaxKind.InvocationExpression) { if (!(analysisContext.SemanticModel.GetSymbolInfo(expr.Expression).Symbol is IMethodSymbol invocationSymbol)) { // Presumably, if the user has typed something but it doesn't have a symbol yet, the body won't be empty // once all compile errors are corrected, so we return false here. return(false); } var conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(analysisContext.SemanticModel.Compilation); return(InvocationIsConditional(invocationSymbol, conditionalAttributeSymbol)); } } return(false); }
public override void Initialize(AnalysisContext context) { // TODO: Consider making this analyzer thread-safe. //context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol obsoleteAttribute = WellKnownTypes.ObsoleteAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create( conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute, obsoleteAttribute); UnusedParameterDictionary unusedMethodParameters = new ConcurrentDictionary <IMethodSymbol, ISet <IParameterSymbol> >(); ISet <IMethodSymbol> methodsUsedAsDelegates = new HashSet <IMethodSymbol>(); // Create a list of functions to exclude from analysis. We assume that any function that is used in an IMethodBindingExpression // cannot have its signature changed, and add it to the list of methods to be excluded from analysis. compilationStartContext.RegisterOperationActionInternal(operationContext => { var methodBinding = (IMethodBindingExpression)operationContext.Operation; methodsUsedAsDelegates.Add(methodBinding.Method.OriginalDefinition); }, OperationKind.MethodBindingExpression); compilationStartContext.RegisterOperationBlockStartActionInternal(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMember() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Ignore methods that were used as delegates if (methodsUsedAsDelegates.Contains(method)) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method, unusedMethodParameters); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationActionInternal(analyzer.AnalyzeOperation, OperationKind.ParameterReferenceExpression); // Register an end action to add unused parameters to the unusedMethodParameters dictionary startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); // Register a compilation end action to filter all methods used as delegates and report any diagnostics compilationStartContext.RegisterCompilationEndAction(compilationAnalysisContext => { // Report diagnostics for unused parameters. var unusedParameters = unusedMethodParameters.Where(kvp => !methodsUsedAsDelegates.Contains(kvp.Key)).SelectMany(kvp => kvp.Value); foreach (var parameter in unusedParameters) { var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], parameter.Name, parameter.ContainingSymbol.Name); compilationAnalysisContext.ReportDiagnostic(diagnostic); } }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol localizableStateAttributeSymbol = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation); INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation); INamedTypeSymbol systemConsoleSymbol = WellKnownTypes.Console(compilationContext.Compilation); ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation); compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } var lazyValueContentResult = new Lazy <DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> >( valueFactory: ComputeValueContentAnalysisResult, isThreadSafe: false); operationBlockStartContext.RegisterOperationAction(operationContext => { var argument = (IArgumentOperation)operationContext.Operation; IMethodSymbol targetMethod = null; switch (argument.Parent) { case IInvocationOperation invocation: targetMethod = invocation.TargetMethod; break; case IObjectCreationOperation objectCreation: targetMethod = objectCreation.Constructor; break; } if (ShouldAnalyze(targetMethod)) { AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic); } }, OperationKind.Argument); operationBlockStartContext.RegisterOperationAction(operationContext => { var propertyReference = (IPropertyReferenceOperation)operationContext.Operation; if (propertyReference.Parent is IAssignmentOperation assignment && assignment.Target == propertyReference && !propertyReference.Property.IsIndexer && propertyReference.Property.SetMethod?.Parameters.Length == 1 && ShouldAnalyze(propertyReference.Property)) { IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0]; AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic); } }, OperationKind.PropertyReference); return; // Local functions bool ShouldAnalyze(ISymbol symbol) => symbol != null && !symbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, Rule, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken); void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic) { if (ShouldBeLocalized(parameter.OriginalDefinition, containingPropertySymbolOpt?.OriginalDefinition, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore) && lazyValueContentResult.Value != null) { ValueContentAbstractValue stringContentValue = lazyValueContentResult.Value[operation.Kind, operation.Syntax]; if (stringContentValue.IsLiteralState) { Debug.Assert(stringContentValue.LiteralValues.Count > 0); if (stringContentValue.LiteralValues.Any(l => !(l is string))) { return; } var stringLiteralValues = stringContentValue.LiteralValues.Select(l => (string)l); // FxCop compat: Do not fire if the literal value came from a default parameter value if (stringContentValue.LiteralValues.Count == 1 && parameter.IsOptional && parameter.ExplicitDefaultValue is string defaultValue && defaultValue == stringLiteralValues.Single()) { return; } // FxCop compat: Do not fire if none of the string literals have any non-control character. if (!LiteralValuesHaveNonControlCharacters(stringLiteralValues)) { return; } // FxCop compat: Filter out xml string literals. var filteredStrings = stringLiteralValues.Where(literal => !LooksLikeXmlTag(literal)); if (filteredStrings.Any()) { // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}". var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var arg3 = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg4 = FormatLiteralValues(filteredStrings); var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4); reportDiagnostic(diagnostic); } } } } DataFlowAnalysisResult <ValueContentBlockAnalysisResult, ValueContentAbstractValue> ComputeValueContentAnalysisResult() { var cfg = operationBlockStartContext.OperationBlocks.GetControlFlowGraph(); if (cfg != null) { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); return(ValueContentAnalysis.TryGetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, operationBlockStartContext.Options, Rule, operationBlockStartContext.CancellationToken)); } return(null); } }); }); }
public override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create(conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (startOperationBlockContext.OwningSymbol.Kind != SymbolKind.Method) { return; } // We only care about methods with parameters. var method = (IMethodSymbol)startOperationBlockContext.OwningSymbol; if (method.Parameters.IsEmpty) { return; } // Ignore implicitly declared methods, abstract methods, virtual methods, interface implementations and finalizers (FxCop compat). if (method.IsImplicitlyDeclared || method.IsAbstract || method.IsVirtual || method.IsOverride || method.IsImplementationOfAnyInterfaceMethod() || method.IsFinalizer()) { return; } // Ignore event handler methods "Handler(object, MyEventArgs)" if (eventsArgSymbol != null && method.Parameters.Length == 2 && method.Parameters[0].Type.SpecialType == SpecialType.System_Object && method.Parameters[1].Type.Inherits(eventsArgSymbol)) { return; } // Ignore methods with any attributes in 'attributeSetForMethodsToIgnore'. if (method.GetAttributes().Any(a => a.AttributeClass != null && attributeSetForMethodsToIgnore.Contains(a.AttributeClass))) { return; } // Initialize local mutable state in the start action. var analyzer = new UnusedParametersAnalyzer(method); // Register an intermediate non-end action that accesses and modifies the state. startOperationBlockContext.RegisterOperationAction(analyzer.AnalyzeOperation, OperationKind.ParameterReferenceExpression); // Register an end action to report diagnostics based on the final state. startOperationBlockContext.RegisterOperationBlockEndAction(analyzer.OperationBlockEndAction); }); }); }
#pragma warning disable RS1026 // Enable concurrent execution public override void Initialize(AnalysisContext context) #pragma warning restore RS1026 // Enable concurrent execution { // TODO: Consider making this analyzer thread-safe. //context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationStartContext => { INamedTypeSymbol eventsArgSymbol = compilationStartContext.Compilation.GetTypeByMetadataName("System.EventArgs"); // Ignore conditional methods (FxCop compat - One conditional will often call another conditional method as its only use of a parameter) INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationStartContext.Compilation); // Ignore methods with special serialization attributes (FxCop compat - All serialization methods need to take 'StreamingContext') INamedTypeSymbol onDeserializingAttribute = WellKnownTypes.OnDeserializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onDeserializedAttribute = WellKnownTypes.OnDeserializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializingAttribute = WellKnownTypes.OnSerializingAttribute(compilationStartContext.Compilation); INamedTypeSymbol onSerializedAttribute = WellKnownTypes.OnSerializedAttribute(compilationStartContext.Compilation); INamedTypeSymbol obsoleteAttribute = WellKnownTypes.ObsoleteAttribute(compilationStartContext.Compilation); ImmutableHashSet <INamedTypeSymbol> attributeSetForMethodsToIgnore = ImmutableHashSet.Create( conditionalAttributeSymbol, onDeserializedAttribute, onDeserializingAttribute, onSerializedAttribute, onSerializingAttribute, obsoleteAttribute); UnusedParameterDictionary unusedMethodParameters = new ConcurrentDictionary <IMethodSymbol, ISet <IParameterSymbol> >(); ISet <IMethodSymbol> methodsUsedAsDelegates = new HashSet <IMethodSymbol>(); // Create a list of functions to exclude from analysis. We assume that any function that is used in an IMethodBindingExpression // cannot have its signature changed, and add it to the list of methods to be excluded from analysis. compilationStartContext.RegisterOperationAction(operationContext => { var methodBinding = (IMethodReferenceOperation)operationContext.Operation; methodsUsedAsDelegates.Add(methodBinding.Method.OriginalDefinition); }, OperationKind.MethodReference); compilationStartContext.RegisterOperationBlockStartAction(startOperationBlockContext => { // We only care about methods. if (!(startOperationBlockContext.OwningSymbol is IMethodSymbol method)) { return; } AnalyzeMethod(method, startOperationBlockContext, unusedMethodParameters, eventsArgSymbol, methodsUsedAsDelegates, attributeSetForMethodsToIgnore); foreach (var localFunctionOperation in startOperationBlockContext.OperationBlocks.SelectMany(o => o.Descendants()).OfType <ILocalFunctionOperation>()) { AnalyzeMethod(localFunctionOperation.Symbol, startOperationBlockContext, unusedMethodParameters, eventsArgSymbol, methodsUsedAsDelegates, attributeSetForMethodsToIgnore); } }); // Register a compilation end action to filter all methods used as delegates and report any diagnostics compilationStartContext.RegisterCompilationEndAction(compilationAnalysisContext => { // Report diagnostics for unused parameters. var unusedParameters = unusedMethodParameters.Where(kvp => !methodsUsedAsDelegates.Contains(kvp.Key)).SelectMany(kvp => kvp.Value); foreach (var parameter in unusedParameters) { var diagnostic = Diagnostic.Create(Rule, parameter.Locations[0], parameter.Name, parameter.ContainingSymbol.Name); compilationAnalysisContext.ReportDiagnostic(diagnostic); } }); }); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol localizableStateAttributeSymbol = WellKnownTypes.LocalizableAttribute(compilationContext.Compilation); INamedTypeSymbol conditionalAttributeSymbol = WellKnownTypes.ConditionalAttribute(compilationContext.Compilation); INamedTypeSymbol systemConsoleSymbol = WellKnownTypes.Console(compilationContext.Compilation); ImmutableHashSet <INamedTypeSymbol> typesToIgnore = GetTypesToIgnore(compilationContext.Compilation); compilationContext.RegisterOperationBlockStartAction(operationBlockStartContext => { if (!(operationBlockStartContext.OwningSymbol is IMethodSymbol containingMethod)) { return; } var lazyStringContentResult = new Lazy <DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> >( valueFactory: ComputeStringContentAnalysisResult, isThreadSafe: false); operationBlockStartContext.RegisterOperationAction(operationContext => { var argument = (IArgumentOperation)operationContext.Operation; switch (argument.Parent?.Kind) { case OperationKind.Invocation: case OperationKind.ObjectCreation: AnalyzeArgument(argument.Parameter, containingPropertySymbolOpt: null, operation: argument, reportDiagnostic: operationContext.ReportDiagnostic); return; } }, OperationKind.Argument); operationBlockStartContext.RegisterOperationAction(operationContext => { var propertyReference = (IPropertyReferenceOperation)operationContext.Operation; if (propertyReference.Parent is IAssignmentOperation assignment && assignment.Target == propertyReference && !propertyReference.Property.IsIndexer && propertyReference.Property.SetMethod?.Parameters.Length == 1) { IParameterSymbol valueSetterParam = propertyReference.Property.SetMethod.Parameters[0]; AnalyzeArgument(valueSetterParam, propertyReference.Property, assignment, operationContext.ReportDiagnostic); } }, OperationKind.PropertyReference); void AnalyzeArgument(IParameterSymbol parameter, IPropertySymbol containingPropertySymbolOpt, IOperation operation, Action <Diagnostic> reportDiagnostic) { if (ShouldBeLocalized(parameter, containingPropertySymbolOpt, localizableStateAttributeSymbol, conditionalAttributeSymbol, systemConsoleSymbol, typesToIgnore)) { StringContentAbstractValue stringContentValue = lazyStringContentResult.Value[operation]; if (stringContentValue.IsLiteralState) { Debug.Assert(stringContentValue.LiteralValues.Count > 0); // FxCop compat: Do not fire if the literal value came from a default parameter value if (stringContentValue.LiteralValues.Count == 1 && parameter.IsOptional && parameter.ExplicitDefaultValue is string defaultValue && defaultValue == stringContentValue.LiteralValues.Single()) { return; } // FxCop compat: Do not fire if none of the string literals have any non-control character. if (!LiteralValuesHaveNonControlCharacters(stringContentValue.LiteralValues)) { return; } // FxCop compat: Filter out xml string literals. var filteredStrings = stringContentValue.LiteralValues.Where(literal => !LooksLikeXmlTag(literal)); if (filteredStrings.Any()) { // Method '{0}' passes a literal string as parameter '{1}' of a call to '{2}'. Retrieve the following string(s) from a resource table instead: "{3}". var arg1 = containingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg2 = parameter.Name; var arg3 = parameter.ContainingSymbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); var arg4 = FormatLiteralValues(filteredStrings); var diagnostic = operation.CreateDiagnostic(Rule, arg1, arg2, arg3, arg4); reportDiagnostic(diagnostic); } } } } DataFlowAnalysisResult <StringContentBlockAnalysisResult, StringContentAbstractValue> ComputeStringContentAnalysisResult() { foreach (var operationRoot in operationBlockStartContext.OperationBlocks) { IBlockOperation topmostBlock = operationRoot.GetTopmostParentBlock(); if (topmostBlock != null) { var cfg = ControlFlowGraph.Create(topmostBlock); var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(operationBlockStartContext.Compilation); var pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider); var copyAnalysisResult = CopyAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResultOpt: pointsToAnalysisResult); // Do another analysis pass to improve the results from PointsTo and Copy analysis. pointsToAnalysisResult = PointsToAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, pointsToAnalysisResult, copyAnalysisResult); return(StringContentAnalysis.GetOrComputeResult(cfg, containingMethod, wellKnownTypeProvider, copyAnalysisResult, pointsToAnalysisResult)); } } return(null); } }); }); }
private bool HasConditionalAttribute(SyntaxNode root, SemanticModel model) { var node = root as InvocationExpressionSyntax; if (node != null) { var exp = node.Expression as MemberAccessExpressionSyntax; if (exp != null) { var symbol = model.GetSymbolInfo(exp.Name).Symbol; if (symbol != null && symbol.GetAttributes().Any(n => n.AttributeClass.Equals(WellKnownTypes.ConditionalAttribute(model.Compilation)))) { return(true); } } } return(false); }