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))); }
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); }
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); }
/// <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); }
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); } } }
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)))); } }
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)))); }
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))); }
/// <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>()); }
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 }