예제 #1
0
        protected bool IsIgnoringInspectionResultFor(Declaration declaration, string inspectionName)
        {
            var module = Declaration.GetModuleParent(declaration);

            if (module == null)
            {
                return(false);
            }

            var isIgnoredAtModuleLevel = module.Annotations
                                         .Any(annotation => annotation.AnnotationType == AnnotationType.IgnoreModule &&
                                              ((IgnoreModuleAnnotation)annotation).IsIgnored(inspectionName));


            if (declaration.DeclarationType == DeclarationType.Parameter)
            {
                return(isIgnoredAtModuleLevel || declaration.ParentDeclaration.Annotations.Any(annotation =>
                                                                                               annotation.AnnotationType == AnnotationType.Ignore &&
                                                                                               ((IgnoreAnnotation)annotation).IsIgnored(inspectionName)));
            }

            return(isIgnoredAtModuleLevel || declaration.Annotations.Any(annotation =>
                                                                         annotation.AnnotationType == AnnotationType.Ignore &&
                                                                         ((IgnoreAnnotation)annotation).IsIgnored(inspectionName)));
        }
예제 #2
0
        public static bool IsMemberAccessible(Declaration callingProject, Declaration callingModule, Declaration callingParent, Declaration calleeMember)
        {
            if (IsEnclosingModule(callingModule, calleeMember))
            {
                return(true);
            }
            var callerIsSubroutineOrProperty = callingParent.DeclarationType.HasFlag(DeclarationType.Property) ||
                                               callingParent.DeclarationType.HasFlag(DeclarationType.Function) ||
                                               callingParent.DeclarationType.HasFlag(DeclarationType.Procedure);
            var calleeHasSameParent = callingParent.Equals(callingParent.ParentScopeDeclaration);

            if (callerIsSubroutineOrProperty && calleeHasSameParent)
            {
                return(calleeHasSameParent);
            }
            var memberModule = Declaration.GetModuleParent(calleeMember);

            if (IsModuleAccessible(callingProject, callingModule, memberModule))
            {
                if (calleeMember.DeclarationType.HasFlag(DeclarationType.EnumerationMember) || calleeMember.DeclarationType.HasFlag(DeclarationType.UserDefinedTypeMember))
                {
                    return(IsValidAccessibility(calleeMember.ParentDeclaration));
                }
                else
                {
                    return(IsValidAccessibility(calleeMember));
                }
            }
            return(false);
        }
예제 #3
0
        protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
        {
            var qualifiers = base.GetQualifierCandidates(reference, finder);

            return(Declaration.GetModuleParent(reference.ParentScoping) is DocumentModuleDeclaration document &&
                   document.SupertypeNames.Contains("Workbook") &&
                   !qualifiers.Any());
        }
        private static bool TargetIsNonPrivateInNonStandardModule(Declaration target)
        {
            if (!target.ParentScopeDeclaration.DeclarationType.HasFlag(DeclarationType.Module))
            {
                //local variable
                return(false);
            }

            return(target.Accessibility != Accessibility.Private &&
                   Declaration.GetModuleParent(target).DeclarationType != DeclarationType.ProceduralModule);
        }
        private static bool IsClassLifeCycleHandler(Declaration procedure)
        {
            if (!ClassLifeCycleHandlers.Contains(procedure.IdentifierName))
            {
                return(false);
            }

            var parent = Declaration.GetModuleParent(procedure);

            return(parent != null &&
                   parent.DeclarationType.HasFlag(DeclarationType.ClassModule));
        }
        private static bool TargetIsInDifferentNonStandardModule(Declaration target)
        {
            var firstReference = target.References.FirstOrDefault();

            if (firstReference == null)
            {
                return(false);
            }

            return(!target.QualifiedModuleName.Equals(firstReference.QualifiedModuleName) &&
                   Declaration.GetModuleParent(target).DeclarationType != DeclarationType.ProceduralModule);
        }
예제 #7
0
        /// <remarks>
        /// We cannot determine whether exposed members of standard modules are called or not,
        /// so we assume they are instead of flagging them as "never called".
        /// </remarks>
        private static bool IsPublicModuleMember(Declaration procedure)
        {
            if ((procedure.Accessibility != Accessibility.Implicit &&
                 procedure.Accessibility != Accessibility.Public))
            {
                return(false);
            }

            var parent = Declaration.GetModuleParent(procedure);

            return(parent != null &&
                   parent.DeclarationType.HasFlag(DeclarationType.ProceduralModule));
        }
        private static bool DeclarationIsInsideOptionPrivateModule(Declaration declaration)
        {
            if (declaration.QualifiedName.QualifiedModuleName.ComponentType != ComponentType.StandardModule)
            {
                return(false);
            }

            if (Declaration.GetModuleParent(declaration) is ProceduralModuleDeclaration moduleDeclaration)
            {
                return(moduleDeclaration.IsPrivateModule);
            }

            return(false);
        }
예제 #9
0
        private void AnnotateType(Declaration declaration)
        {
            if (declaration.DeclarationType == DeclarationType.ClassModule ||
                declaration.DeclarationType == DeclarationType.UserDefinedType ||
                declaration.DeclarationType == DeclarationType.ComAlias)
            {
                declaration.AsTypeDeclaration = declaration;
                return;
            }
            string typeExpression;

            if (declaration.AsTypeContext != null && declaration.AsTypeContext.type().complexType() != null)
            {
                var typeContext = declaration.AsTypeContext;
                typeExpression = typeContext.type().complexType().GetText();
            }
            else if (!string.IsNullOrWhiteSpace(declaration.AsTypeNameWithoutArrayDesignator) && !SymbolList.BaseTypes.Contains(declaration.AsTypeNameWithoutArrayDesignator.ToUpperInvariant()))
            {
                typeExpression = declaration.AsTypeNameWithoutArrayDesignator;
            }
            else
            {
                return;
            }
            var module = Declaration.GetModuleParent(declaration);

            if (module == null)
            {
                Logger.Warn("Type annotation failed for {0} because module parent is missing.", typeExpression);
                return;
            }
            var expressionContext = _expressionParser.Parse(typeExpression.Trim());
            var boundExpression   = _bindingService.ResolveType(module, declaration.ParentDeclaration, expressionContext);

            if (boundExpression.Classification != ExpressionClassification.ResolutionFailed)
            {
                declaration.AsTypeDeclaration = boundExpression.ReferencedDeclaration;
            }
            else
            {
                const string IGNORE_THIS = "DISPATCH";
                if (typeExpression != IGNORE_THIS)
                {
                    Logger.Warn("Failed to resolve type {0}", typeExpression);
                }
            }
        }
예제 #10
0
        private static string InterfaceModuleBody(ExtractInterfaceModel model)
        {
            var interfaceMembers = string.Join(NewLines.DOUBLE_SPACE, model.SelectedMembers.Select(m => m.Body));
            var optionExplicit   = $"{Tokens.Option} {Tokens.Explicit}{Environment.NewLine}";

            var targetModule         = Declaration.GetModuleParent(model.TargetDeclaration);
            var folderAnnotation     = targetModule?.Annotations.FirstOrDefault(pta => pta.Annotation is FolderAnnotation);
            var folderAnnotationText = folderAnnotation != null
                                       ? $"'@{folderAnnotation.Context.GetText()}{Environment.NewLine}"
                                       : string.Empty;

            var exposedAnnotation     = new ExposedModuleAnnotation();
            var exposedAnnotationText = model.InterfaceInstancing == ClassInstancing.Public
                ? $"'@{exposedAnnotation.Name}{Environment.NewLine}"
                : string.Empty;

            var interfaceAnnotation     = new InterfaceAnnotation();
            var interfaceAnnotationText = $"'@{interfaceAnnotation.Name}{Environment.NewLine}";

            return($"{optionExplicit}{Environment.NewLine}{folderAnnotationText}{exposedAnnotationText}{interfaceAnnotationText}{Environment.NewLine}{interfaceMembers}");
        }
        protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
        {
            var qualifiers  = base.GetQualifierCandidates(reference, finder);
            var isQualified = qualifiers.Any();
            var document    = Declaration.GetModuleParent(reference.ParentNonScoping) as DocumentModuleDeclaration;

            var isHostWorkbook = (document?.SupertypeNames.Contains("Workbook") ?? false) &&
                                 (document?.ProjectId?.Equals(reference.QualifiedModuleName.ProjectId) ?? false);

            if (!isQualified)
            {
                // unqualified calls aren't referring to ActiveWorkbook only inside a Workbook module:
                return(!isHostWorkbook);
            }
            else
            {
                if (_applicationCandidates == null)
                {
                    var applicationClass = finder.FindClassModule("Application", base.Excel, includeBuiltIn: true);
                    // note: underscored declarations would be for unqualified calls
                    var workbookClass  = finder.FindClassModule("Workbook", base.Excel, includeBuiltIn: true);
                    var worksheetClass = finder.FindClassModule("Worksheet", base.Excel, includeBuiltIn: true);
                    var hostBook       = finder.UserDeclarations(DeclarationType.Document)
                                         .Cast <DocumentModuleDeclaration>()
                                         .SingleOrDefault(doc => doc.ProjectId.Equals(reference.QualifiedModuleName.ProjectId) &&
                                                          doc.SupertypeNames.Contains("Workbook"));

                    _applicationCandidates = finder.MatchName("Application")
                                             .Where(m => m.Equals(applicationClass) ||
                                                    (m.ParentDeclaration.Equals(workbookClass) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet)) ||
                                                    (m.ParentDeclaration.Equals(worksheetClass) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet)) ||
                                                    (m.ParentDeclaration.Equals(hostBook) && m.DeclarationType.HasFlag(DeclarationType.PropertyGet)))
                                             .ToList();
                }

                // qualified calls are referring to ActiveWorkbook if qualifier is the Application object:
                return(_applicationCandidates.Any(candidate => qualifiers.Any(q => q.Equals(candidate))));
            }
        }
예제 #12
0
        public static bool IsMemberAccessible(Declaration callingProject, Declaration callingModule, Declaration callingParent, Declaration calleeMember)
        {
            if (calleeMember == null)
            {
                return(false);
            }
            if (IsInstanceMemberOfModuleOrOneOfItsSupertypes(callingModule, calleeMember) ||
                IsLocalMemberOfTheCallingSubroutineOrProperty(callingParent, calleeMember))
            {
                return(true);
            }
            if (!calleeMember.IsUserDefined && calleeMember.Accessibility > Accessibility.Friend)
            {
                return(true);
            }
            var memberModule = Declaration.GetModuleParent(calleeMember);

            return(IsModuleAccessible(callingProject, callingModule, memberModule) &&
                   (calleeMember.DeclarationType.HasFlag(DeclarationType.EnumerationMember) ||
                    calleeMember.DeclarationType.HasFlag(DeclarationType.UserDefinedTypeMember) ||
                    calleeMember.DeclarationType.HasFlag(DeclarationType.ComAlias) ||
                    HasPublicScope(calleeMember) ||
                    (IsEnclosingProject(callingProject, memberModule) && IsAccessibleThroughoutTheSameProject(calleeMember))));
        }
예제 #13
0
 private static bool HasModuleIgnoreFor(this Declaration declaration, string inspectionName)
 {
     return(Declaration.GetModuleParent(declaration)?.Annotations
            .Where(pta => pta.Annotation is IgnoreModuleAnnotation)
            .Any(ignoreModule => !ignoreModule.AnnotationArguments.Any() || ignoreModule.AnnotationArguments.Contains(inspectionName)) ?? false);
 }
 protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
 {
     return(!(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document) ||
            !document.SupertypeNames.Contains("Worksheet"));
 }
        /// <summary>
        /// Determines whether the 'Set' keyword is required (whether it's present or not) for the specified identifier reference.
        /// </summary>
        /// <param name="reference">The identifier reference to analyze</param>
        /// <param name="declarationFinderProvider">The parser state</param>
        public static bool RequiresSetAssignment(IdentifierReference reference, IDeclarationFinderProvider declarationFinderProvider)
        {
            if (!reference.IsAssignment)
            {
                // reference isn't assigning its declaration; not interesting
                return(false);
            }

            if (reference.IsSetAssignment)
            {
                // don't assume Set keyword is legit...
                return(reference.Declaration.IsObject);
            }

            var declaration = reference.Declaration;

            if (declaration.IsArray)
            {
                // arrays don't need a Set statement... todo figure out if array items are objects
                return(false);
            }

            var isObjectVariable = declaration.IsObject;

            if (!isObjectVariable && !(declaration.IsUndeclared || Tokens.Variant.Equals(declaration.AsTypeName)))
            {
                return(false);
            }

            // For Each iterators are implicitly set.
            var letStmtContext = reference.Context.GetAncestor <VBAParser.LetStmtContext>();

            if (reference.Context.GetAncestor <VBAParser.ForEachStmtContext>() != null && letStmtContext == null)
            {
                return(false);
            }

            if (isObjectVariable)
            {
                // get the members of the returning type, a default member could make us lie otherwise
                var classModule = declaration.AsTypeDeclaration as ClassModuleDeclaration;
                if (classModule?.DefaultMember == null)
                {
                    return(true);
                }
                var parameters = (classModule.DefaultMember as IParameterizedDeclaration)?.Parameters;
                // assign declaration is an object without a default parameterless (or with all parameters optional) member - LHS needs a 'Set' keyword.
                return(parameters != null && parameters.All(p => p.IsOptional));
            }

            // assigned declaration is a variant. we need to know about the RHS of the assignment.
            if (letStmtContext == null)
            {
                // not an assignment
                return(false);
            }

            var expression = letStmtContext.expression();

            if (expression == null)
            {
                Debug.Assert(false, "RHS expression is empty? What's going on here?");
                return(false);
            }

            if (expression is VBAParser.NewExprContext)
            {
                // RHS expression is newing up an object reference - LHS needs a 'Set' keyword:
                return(true);
            }

            var literalExpression = expression as VBAParser.LiteralExprContext;

            if (literalExpression?.literalExpression()?.literalIdentifier()?.objectLiteralIdentifier() != null)
            {
                // RHS is a 'Nothing' token - LHS needs a 'Set' keyword:
                return(true);
            }
            if (literalExpression != null)
            {
                return(false); // any other literal expression definitely isn't an object.
            }

            // todo resolve expression return type
            var project = Declaration.GetProjectParent(reference.ParentScoping);
            var module  = Declaration.GetModuleParent(reference.ParentScoping);

            var simpleName = expression.GetDescendent <VBAParser.SimpleNameExprContext>();

            if (simpleName != null)
            {
                return(declarationFinderProvider.DeclarationFinder.MatchName(simpleName.identifier().GetText())
                       .Any(d => AccessibilityCheck.IsAccessible(project, module, reference.ParentScoping, d) && d.IsObject));
            }

            // is the reference referring to something else in scope that's a object?
            return(declarationFinderProvider.DeclarationFinder.MatchName(expression.GetText())
                   .Any(decl => (decl.DeclarationType.HasFlag(DeclarationType.ClassModule) || Tokens.Object.Equals(decl.AsTypeName)) &&
                        AccessibilityCheck.IsAccessible(project, module, reference.ParentScoping, decl)));
        }
예제 #16
0
        /// <summary>
        /// Determines whether the 'Set' keyword is required (whether it's present or not) for the specified identifier reference.
        /// </summary>
        /// <param name="reference">The identifier reference to analyze</param>
        /// <param name="declarationFinderProvider">The parser state</param>
        public static bool RequiresSetAssignment(IdentifierReference reference, IDeclarationFinderProvider declarationFinderProvider)
        {
            if (!reference.IsAssignment)
            {
                // reference isn't assigning its declaration; not interesting
                return(false);
            }

            if (reference.IsSetAssignment)
            {
                // don't assume Set keyword is legit...
                return(reference.Declaration.IsObject);
            }

            var declaration = reference.Declaration;

            if (declaration.IsArray)
            {
                // arrays don't need a Set statement... todo figure out if array items are objects
                return(false);
            }

            var isObjectVariable = declaration.IsObject;

            if (!isObjectVariable && !(declaration.IsUndeclared || Tokens.Variant.Equals(declaration.AsTypeName)))
            {
                return(false);
            }

            // For Each iterators are implicitly set.
            var letStmtContext = reference.Context.GetAncestor <VBAParser.LetStmtContext>();

            if (reference.Context.GetAncestor <VBAParser.ForEachStmtContext>() != null && letStmtContext == null)
            {
                return(false);
            }

            if (isObjectVariable)
            {
                // get the members of the returning type, a default member could make us lie otherwise
                var classModule = declaration.AsTypeDeclaration as ClassModuleDeclaration;
                return(!HasPotentiallyNonObjectParameterlessDefaultMember(classModule));
            }

            // assigned declaration is a variant. we need to know about the RHS of the assignment.
            if (letStmtContext == null)
            {
                // not an assignment
                return(false);
            }

            var expression = letStmtContext.expression();

            if (expression == null)
            {
                Debug.Assert(false, "RHS expression is empty? What's going on here?");
                return(false);
            }


            var module = Declaration.GetModuleParent(reference.ParentScoping);

            if (expression is VBAParser.NewExprContext newExpr)
            {
                var newTypeExpression = newExpr.expression();

                // todo resolve expression type

                //Covers the case of a single type on the RHS of the assignment.
                var simpleTypeName = newTypeExpression.GetDescendent <VBAParser.SimpleNameExprContext>();
                if (simpleTypeName != null && simpleTypeName.GetText() == newTypeExpression.GetText())
                {
                    var qualifiedIdentifierSelection = new QualifiedSelection(module.QualifiedModuleName,
                                                                              simpleTypeName.identifier().GetSelection());
                    var identifierText = simpleTypeName.identifier().GetText();
                    return(declarationFinderProvider.DeclarationFinder.IdentifierReferences(qualifiedIdentifierSelection)
                           .Select(identifierReference => identifierReference.Declaration)
                           .Where(decl => identifierText == decl.IdentifierName)
                           .OfType <ClassModuleDeclaration>()
                           .Any(typeDecl => !HasPotentiallyNonObjectParameterlessDefaultMember(typeDecl)));
                }
                //Here, we err on the side of false-positives, but that seems more appropriate than not to treat qualified type expressions incorrectly.
                //Whether there is a legitimate use here for default members is questionable anyway.
                return(true);
            }

            var literalExpression = expression as VBAParser.LiteralExprContext;

            if (literalExpression?.literalExpression()?.literalIdentifier()?.objectLiteralIdentifier() != null)
            {
                // RHS is a 'Nothing' token - LHS needs a 'Set' keyword:
                return(true);
            }
            if (literalExpression != null)
            {
                return(false); // any other literal expression definitely isn't an object.
            }

            // todo resolve expression return type

            //Covers the case of a single variable on the RHS of the assignment.
            var simpleName = expression.GetDescendent <VBAParser.SimpleNameExprContext>();

            if (simpleName != null && simpleName.GetText() == expression.GetText())
            {
                var qualifiedIdentifierSelection = new QualifiedSelection(module.QualifiedModuleName,
                                                                          simpleName.identifier().GetSelection());
                return(declarationFinderProvider.DeclarationFinder.IdentifierReferences(qualifiedIdentifierSelection)
                       .Select(identifierReference => identifierReference.Declaration)
                       .Where(decl => decl.IsObject &&
                              simpleName.identifier().GetText() == decl.IdentifierName)
                       .Select(typeDeclaration => typeDeclaration.AsTypeDeclaration as ClassModuleDeclaration)
                       .Any(typeDecl => !HasPotentiallyNonObjectParameterlessDefaultMember(typeDecl)));
            }

            var project = Declaration.GetProjectParent(reference.ParentScoping);

            //todo: Use code path analysis to ensure that we are really picking up the last assignment to the RHS.
            // is the reference referring to something else in scope that's a object?
            return(declarationFinderProvider.DeclarationFinder.MatchName(expression.GetText())
                   .Any(decl => (decl.DeclarationType.HasFlag(DeclarationType.ClassModule) || Tokens.Object.Equals(decl.AsTypeName)) &&
                        AccessibilityCheck.IsAccessible(project, module, reference.ParentScoping, decl)));
        }
 protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
 {
     return(!(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document) ||
            !document.SupertypeNames.Contains("Workbook") ||
            _alwaysActiveWorkbookReferenceParents.Contains(reference.Declaration.ParentDeclaration.IdentifierName));
 }
        /// <summary>
        /// Gets the possible <see cref="Declaration"/> that qualifies an identifier reference in a member access expression.
        /// </summary>
        protected IEnumerable <Declaration> GetQualifierCandidates(IdentifierReference reference, DeclarationFinder finder)
        {
            if (reference.Context.TryGetAncestor <VBAParser.MemberAccessExprContext>(out var memberAccess))
            {
                var parentModule         = Declaration.GetModuleParent(reference.ParentScoping);
                var qualifyingExpression = memberAccess.lExpression();
                if (qualifyingExpression is VBAParser.SimpleNameExprContext simpleName)
                {
                    if (simpleName.GetText().Equals(Tokens.Me, System.StringComparison.InvariantCultureIgnoreCase))
                    {
                        // qualifier is 'Me'
                        return(new[] { parentModule });
                    }

                    // todo get the actual qualifying declaration?
                    return(finder.MatchName(simpleName.GetText())
                           .Where(candidate => !candidate.IdentifierName.Equals(reference.Declaration.IdentifierName, System.StringComparison.InvariantCultureIgnoreCase)));
                }

                if (qualifyingExpression.ChildCount == 1 && qualifyingExpression.GetText().Equals(Tokens.Me, System.StringComparison.InvariantCultureIgnoreCase))
                {
                    // qualifier is 'Me'
                    return(new[] { parentModule });
                }
            }

            if (reference.Context.TryGetAncestor <VBAParser.WithMemberAccessExprContext>(out var dot))
            {
                // qualifier is a With block
                var withBlock = dot.GetAncestor <VBAParser.WithStmtContext>();
                return(finder.ContainedIdentifierReferences(new QualifiedSelection(reference.QualifiedModuleName, withBlock.GetSelection()))
                       .Select(r => r.Declaration).Distinct()
                       .Where(candidate => !candidate.Equals(reference.Declaration)));
            }

            if (reference.Context.TryGetAncestor <VBAParser.CallStmtContext>(out var callStmt))
            {
                if (reference.Context.TryGetAncestor <VBAParser.LExpressionContext>(out var lExpression))
                {
                    // reference is in lexpression of a call statement

                    if (lExpression is VBAParser.MemberAccessExprContext member)
                    {
                        if (member.lExpression() is VBAParser.SimpleNameExprContext name)
                        {
                            if (reference.IdentifierName.Equals(name.identifier().GetText(), System.StringComparison.InvariantCultureIgnoreCase))
                            {
                                // unqualified
                                return(Enumerable.Empty <Declaration>());
                            }

                            return(finder.MatchName(name.identifier().GetText())
                                   .Where(candidate => !candidate.Equals(reference.Declaration)));
                        }

                        // todo get the actual qualifying declaration?
                        return(finder.MatchName(member.lExpression().children.First().GetText())
                               .Where(candidate => !candidate.Equals(reference.Declaration)));
                    }
                }
            }

            return(Enumerable.Empty <Declaration>());
        }
예제 #19
0
 protected override bool IsResultReference(IdentifierReference reference, DeclarationFinder finder)
 {
     return(Declaration.GetModuleParent(reference.ParentNonScoping) is DocumentModuleDeclaration document &&
            document.SupertypeNames.Contains("Worksheet") &&
            !(reference.Context.Parent is Parsing.Grammar.VBAParser.MemberAccessExprContext));   // if it's qualified, it's not an implicit reference
 }