-
Notifications
You must be signed in to change notification settings - Fork 74
Michaelrfairhurst/package deadcode 9 rule 0-2-3 #1043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| - `RULE-2-3`, `A0-1-6` - `UnusedTypeDeclarations.ql`: | ||
| - Type usage analysis has been improved to find more possible type usages, including: | ||
| - Previous behavior considered anonymous types in variable declarations to be considered used by the variable definition itself. This has been improved to require that a field of the anonymous type is accessed for the type to be considered used. | ||
| - Usages of a template type inside a specialization of that template are no longer considered usages of the template type. | ||
| - Hidden friend declarations are no longer considered usages of the class they are declaring friendship for. | ||
| - Improved exclusions generally, for cases such as nested types and functions within functions. These previously were a source of incorrectly identified type uses. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import cpp | ||
|
|
||
| /** | ||
| * The last declaration in a class by location order. | ||
| * | ||
| * This may fail to capture certain cases such as hidden friends (see HiddenFriend.qll). | ||
| */ | ||
| class LastClassDeclaration extends Declaration { | ||
| Class cls; | ||
|
|
||
| pragma[nomagic] | ||
| LastClassDeclaration() { | ||
| this = | ||
| max(Declaration decl, Location l | | ||
| decl = cls.getADeclaration() and | ||
| l = decl.getLocation() | ||
| | | ||
| decl order by l.getEndLine(), l.getEndColumn() | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /** | ||
| * The C++ extractor does not support hidden friends, which are friend functions defined within a | ||
| * class, rather than declared: | ||
| * | ||
| * ```cpp | ||
| * struct A { | ||
| * friend void hidden_friend(A) {} // Definition: this is a hidden friend | ||
| * friend void not_hidden_friend(A); // Declaration: this is not a hidden friend | ||
| * }; | ||
| * ``` | ||
| * | ||
| * In the database, a `FriendDecl` is not created for the hidden friend. The hidden friend function | ||
| * is created as a `TopLevel` function with no enclosing element. However, we can identify it as a | ||
| * hidden friend by its location. | ||
| */ | ||
|
|
||
| import cpp | ||
| import codingstandards.cpp.ast.Class | ||
|
|
||
| class PossibleHiddenFriend extends HiddenFriendCandidate { | ||
| ClassCandidate cls; | ||
|
|
||
| PossibleHiddenFriend() { hidesFriend(cls, this) } | ||
|
|
||
| Class getFriendClass() { result = cls } | ||
| } | ||
|
|
||
| /** | ||
| * Begin by limiting the number of candidate functions to consider. | ||
| * | ||
| * Only inline top level functions can be hidden friends. | ||
| */ | ||
| private class HiddenFriendCandidate extends TopLevelFunction { | ||
| HiddenFriendCandidate() { this.isInline() } | ||
| } | ||
|
|
||
| /** | ||
| * Only consider files which contain hidden friend candidates. | ||
| */ | ||
| private class FileCandidate extends File { | ||
| FileCandidate() { exists(HiddenFriendCandidate c | c.getFile() = this) } | ||
| } | ||
|
|
||
| /** | ||
| * Only consider classes in candidate files, that include hidden friend candidates. | ||
| */ | ||
| private class ClassCandidate extends Class { | ||
| ClassCandidate() { getFile() instanceof FileCandidate } | ||
|
|
||
| Declaration getNextSiblingDeclaration() { | ||
| exists(LastClassDeclaration last | | ||
| last.getDeclaringType() = this and | ||
| result = | ||
| min(Declaration decl | | ||
| decl.getEnclosingElement() = this.getEnclosingElement() and | ||
| pragma[only_bind_out](decl.getFile()) = pragma[only_bind_out](this.getFile()) and | ||
| decl.getLocation().getStartLine() > last.getLocation().getEndLine() | ||
| | | ||
| decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn() | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| Declaration getNextOrphanedDeclaration() { | ||
| exists(LastClassDeclaration last | | ||
| last.getDeclaringType() = this and | ||
| result = | ||
| min(OrphanedDeclaration decl, Location locLast, Location locDecl | | ||
| orphanHasFile(decl, this.getFile()) and | ||
| locDecl = decl.getLocation() and | ||
| locLast = last.getLocation() and | ||
| locLast.getStartLine() < locDecl.getEndLine() | ||
| | | ||
| decl order by locDecl.getStartLine(), locDecl.getStartColumn() | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| Declaration getFirstNonClassDeclaration() { | ||
| exists(LastClassDeclaration last | | ||
| last.getDeclaringType() = this and | ||
| result = | ||
| min(Declaration decl | | ||
| decl = getNextSiblingDeclaration() or decl = getNextOrphanedDeclaration() | ||
| | | ||
| decl order by decl.getLocation().getStartLine(), decl.getLocation().getStartColumn() | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| pragma[nomagic] | ||
| private predicate orphanHasFile(OrphanedDeclaration orphan, FileCandidate file) { | ||
| orphan.getFile() = file | ||
| } | ||
|
|
||
| private class OrphanedDeclaration extends Declaration { | ||
| OrphanedDeclaration() { | ||
| not exists(getEnclosingElement()) and | ||
| not this instanceof HiddenFriendCandidate and | ||
| getFile() instanceof FileCandidate and | ||
| not isFromTemplateInstantiation(_) | ||
| } | ||
| } | ||
|
|
||
| pragma[nomagic] | ||
| private predicate classCandidateHasFile(ClassCandidate c, FileCandidate f) { c.getFile() = f } | ||
|
|
||
| pragma[nomagic] | ||
| private predicate hiddenFriendCandidateHasFile(HiddenFriendCandidate h, FileCandidate f) { | ||
| h.getFile() = f | ||
| } | ||
|
|
||
| pragma[nomagic] | ||
| private predicate hidesFriend(ClassCandidate c, HiddenFriendCandidate f) { | ||
| exists(FileCandidate file, Location cloc, Location floc | | ||
| classCandidateHasFile(c, file) and | ||
| hiddenFriendCandidateHasFile(f, file) and | ||
| cloc = c.getLocation() and | ||
| floc = f.getLocation() and | ||
| cloc.getEndLine() < floc.getStartLine() and | ||
| floc.getEndLine() < c.getFirstNonClassDeclaration().getLocation().getStartLine() | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ | ||
| import cpp | ||
| import RuleMetadata | ||
| import codingstandards.cpp.exclusions.RuleMetadata | ||
|
|
||
| newtype DeadCode9Query = TUnusedTypeWithLimitedVisibilityQuery() | ||
|
|
||
| predicate isDeadCode9QueryMetadata(Query query, string queryId, string ruleId, string category) { | ||
| query = | ||
| // `Query` instance for the `unusedTypeWithLimitedVisibility` query | ||
| DeadCode9Package::unusedTypeWithLimitedVisibilityQuery() and | ||
| queryId = | ||
| // `@id` for the `unusedTypeWithLimitedVisibility` query | ||
| "cpp/misra/unused-type-with-limited-visibility" and | ||
| ruleId = "RULE-0-2-3" and | ||
| category = "advisory" | ||
| } | ||
|
|
||
| module DeadCode9Package { | ||
| Query unusedTypeWithLimitedVisibilityQuery() { | ||
| //autogenerate `Query` type | ||
| result = | ||
| // `Query` type for `unusedTypeWithLimitedVisibility` query | ||
| TQueryCPP(TDeadCode9PackageQuery(TUnusedTypeWithLimitedVisibilityQuery())) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |||||||||||||||||||
| */ | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import cpp | ||||||||||||||||||||
| import codingstandards.cpp.ast.HiddenFriend | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /** | ||||||||||||||||||||
| * Gets a typedef with the same qualified name and declared at the same location. | ||||||||||||||||||||
|
|
@@ -35,7 +36,8 @@ private TypedefType getAnEquivalentTypeDef(TypedefType type) { | |||||||||||||||||||
| * is from within the function signature or field declaration of the type itself. | ||||||||||||||||||||
| */ | ||||||||||||||||||||
| Locatable getATypeUse(Type type) { | ||||||||||||||||||||
| result = getATypeUse_i(type, _) | ||||||||||||||||||||
| result = getATypeUse_i(type, _) and | ||||||||||||||||||||
| not isWithinTypeDefinition(result, type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| // Identify `TypeMention`s of typedef types, where the underlying type is used. | ||||||||||||||||||||
| // | ||||||||||||||||||||
|
|
@@ -65,6 +67,39 @@ Locatable getATypeUse(Type type) { | |||||||||||||||||||
| ) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| predicate isWithinTypeDefinition(Locatable loc, Type type) { | ||||||||||||||||||||
| loc = type | ||||||||||||||||||||
| or | ||||||||||||||||||||
| loc.getEnclosingElement*() = type | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(Function).getDeclaringType(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(MemberVariable).getDeclaringType(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(PossibleHiddenFriend).getFriendClass(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(Parameter).getFunction(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(Expr).getEnclosingFunction(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| isWithinTypeDefinition(loc.(LocalVariable).getFunction(), type) | ||||||||||||||||||||
| or | ||||||||||||||||||||
| exists(TemplateClass tpl, ClassTemplateSpecialization spec | | ||||||||||||||||||||
| tpl = type and | ||||||||||||||||||||
| tpl = spec.getPrimaryTemplate() and | ||||||||||||||||||||
| isWithinTypeDefinition(loc, spec) | ||||||||||||||||||||
| ) | ||||||||||||||||||||
| //exists(TemplateClass tpl, ClassTemplateSpecialization spec | | ||||||||||||||||||||
| // tpl.getAnInstantiation() = type and | ||||||||||||||||||||
| // tpl = spec.getPrimaryTemplate() and | ||||||||||||||||||||
| // isWithinTypeDefinition(loc, spec) | ||||||||||||||||||||
| //) | ||||||||||||||||||||
| //exists(ClassTemplateSpecialization spec | | ||||||||||||||||||||
| // specializationSharesType(type, spec) and | ||||||||||||||||||||
| // isWithinTypeDefinition(loc, spec) | ||||||||||||||||||||
| //) | ||||||||||||||||||||
|
Comment on lines
+92
to
+100
|
||||||||||||||||||||
| //exists(TemplateClass tpl, ClassTemplateSpecialization spec | | |
| // tpl.getAnInstantiation() = type and | |
| // tpl = spec.getPrimaryTemplate() and | |
| // isWithinTypeDefinition(loc, spec) | |
| //) | |
| //exists(ClassTemplateSpecialization spec | | |
| // specializationSharesType(type, spec) and | |
| // isWithinTypeDefinition(loc, spec) | |
| //) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * @id cpp/misra/unused-type-with-limited-visibility | ||
| * @name RULE-0-2-3: Types with limited visibility should be used at least once | ||
| * @description Types that are unused with limited visibility are unnecessary and should either be | ||
| * removed or may indicate a developer mistake. | ||
| * @kind problem | ||
| * @precision very-high | ||
| * @problem.severity error | ||
| * @tags external/misra/id/rule-0-2-3 | ||
| * scope/single-translation-unit | ||
| * maintainability | ||
| * correctness | ||
| * external/misra/enforcement/decidable | ||
| * external/misra/obligation/advisory | ||
| */ | ||
|
|
||
| import cpp | ||
| import codingstandards.cpp.misra | ||
| import codingstandards.cpp.types.Uses | ||
|
|
||
| predicate hasLimitedVisibility(UserType type) { | ||
| type.isLocal() or | ||
| type.getNamespace().isAnonymous() | ||
| } | ||
|
|
||
| predicate hasMaybeUnusedAttribute(UserType type) { | ||
| exists(Attribute a | a = type.getAnAttribute() and a.getName() = "maybe_unused") | ||
| } | ||
|
|
||
| from UserType type | ||
| where | ||
| not isExcluded(type, DeadCode9Package::unusedTypeWithLimitedVisibilityQuery()) and | ||
| hasLimitedVisibility(type) and | ||
| not exists(getATypeUse(type)) and | ||
| not hasMaybeUnusedAttribute(type) and | ||
| not type instanceof TypeTemplateParameter and | ||
| not type instanceof ClassTemplateSpecialization | ||
| select type, "Type '" + type.getName() + "' with limited visibility is not used." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| | test.cpp:5:9:5:10 | T1 | Type 'T1' with limited visibility is not used. | | ||
| | test.cpp:22:8:22:9 | A1 | Type 'A1' with limited visibility is not used. | | ||
| | test.cpp:26:8:26:9 | A2 | Type 'A2' with limited visibility is not used. | | ||
| | test.cpp:62:28:62:29 | C1<<unnamed>> | Type 'C1<<unnamed>>' with limited visibility is not used. | | ||
| | test.cpp:79:14:79:14 | (unnamed class/struct/union) | Type '(unnamed class/struct/union)' with limited visibility is not used. | | ||
| | test.cpp:105:12:105:13 | E2 | Type 'E2' with limited visibility is not used. | | ||
| | test.cpp:115:9:115:10 | T2 | Type 'T2' with limited visibility is not used. | | ||
| | test.cpp:126:10:126:11 | S2 | Type 'S2' with limited visibility is not used. | | ||
| | test.cpp:133:8:133:9 | A3 | Type 'A3' with limited visibility is not used. | | ||
| | test.cpp:145:8:145:9 | A6 | Type 'A6' with limited visibility is not used. | | ||
| | test.cpp:152:29:152:42 | AliasTemplate1 | Type 'AliasTemplate1' with limited visibility is not used. | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rules/RULE-0-2-3/UnusedTypeWithLimitedVisibility.ql |
Uh oh!
There was an error while loading. Please reload this page.