Class UnnecessaryFullyQualifiedTypeCheck
java.lang.Object
com.puppycrawl.tools.checkstyle.AbstractAutomaticBean
com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter
com.puppycrawl.tools.checkstyle.api.AbstractCheck
com.puppycrawl.tools.checkstyle.checks.imports.UnnecessaryFullyQualifiedTypeCheck
- All Implemented Interfaces:
Configurable,Contextualizable
Checks for fully qualified type references that are unnecessary because the
type could simply be imported and referenced by its simple name.
A fully qualified type reference, such as java.util.Map, is reported
as unnecessary unless another type with the same simple name is also used in
the file. For example, java.util.Map is allowed only when a different
Map (e.g. com.example.Map, a locally declared Map, or
a same-package or java.lang Map) is also referenced, since in
that case qualification is required to tell the two types apart.
Using fully qualified names where they are not needed reduces readability and is inconsistent with common Java style conventions, which favor importing the type instead.
The following limitations apply:
-
To distinguish a package qualified type (such as
java.util.Map) from a reference to a nested type (such asMap.Entry), the check relies on the common convention that package names start with a lowercase letter. A qualified reference is treated as fully qualified only when the identifier preceding the simple name starts with a lowercase letter. -
References to nested types via an enclosing type (for example
java.util.Map.Entry) and fully qualified annotations (for example@java.lang.Override) are not reported. -
On-demand (wildcard) imports, such as
import java.util.*;, are checked against classes reachable on this check's own class loader. This reliably detects collisions from JDK packages (for example a fully qualified reference to a third-partyObservertype being left alone becauseimport java.util.*;also brings a differentjava.util.Observerinto scope), but on-demand imports of third-party or project-local packages cannot be resolved this way and may still be flagged incorrectly.
- Since:
- 14.1.0
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final recordHolds the details of a fully qualified type reference.Nested classes/interfaces inherited from class com.puppycrawl.tools.checkstyle.AbstractAutomaticBean
AbstractAutomaticBean.OutputStreamOptions -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final StringArray declarator markers that may trail a type name.private static final StringMarker used to represent a locally declared type in the identity set.Simple names of the types declared in the file.private static final StringSeparator used between components of a fully qualified name.Maps the simple name of each single-type import to its fully qualified name.private static final StringThejava.langpackage, types of which never need to be qualified.static final StringA key is pointing to the warning message text in "messages.properties" file.private static final StringSuffix identifying an on-demand (wildcard) import, such asjava.util.*.Packages imported on-demand (wildcard), e.g.private StringThe package the file belongs to, ornullfor the default package.private final List<UnnecessaryFullyQualifiedTypeCheck.QualifiedTypeReference> Fully qualified type references collected while traversing the file.Simple names of the types referenced without qualification in the file.private static final int[]Tokens whose direct child is a type reference.private static final int[]Tokens that declare a type.private static final StringMarker used to represent an unqualified type reference in the identity set. -
Constructor Summary
ConstructorsConstructorDescriptionCreates newUnnecessaryFullyQualifiedTypeCheckinstance. -
Method Summary
Modifier and TypeMethodDescriptionprivate voidaddImplicitIdentities(String simpleName, boolean unqualifiedResolvedToReference, Set<String> identities) Adds identities that are not established by an explicit import: an unqualified reference resolving to a same-package orjava.langtype, and a type reachable via an on-demand import.private voidaddQualifiedReferenceIdentities(String simpleName, Set<String> identities) Adds an identity for each fully qualified reference sharing the given simple name.voidCalled before the starting to process a tree.private static StringbuildFullName(DetailAST ast) Reconstructs the fully qualified name for aTokenTypes#DOTnode, handling the extra child produced by an embedded type-use annotation.collectIdentities(String simpleName) Collects every distinct identity claiming the given simple name in the file: a direct import, each fully qualified reference sharing that simple name, a locally declared type, an unqualified reference resolving elsewhere, and a type reachable via an on-demand import.private static StringextractSimpleName(String name) Extracts the simple name from a qualified name.voidfinishTree(DetailAST rootAST) Called after finished processing a tree.int[]The configurable token set.int[]Returns the default token a check is interested in.int[]The tokens that this check must be registered for.private static booleanisFullyQualified(String name) Determines whether the given qualified name is a package qualified (fully qualified) type reference, as opposed to a reference to a nested type.private static booleanisInTypeContext(DetailAST ast) Checks whether the given node is a direct child of a type context token.private booleanisUnnecessary(String simpleName) Determines whether a type reference with the given simple name is unnecessary.private voidprocessDot(DetailAST ast) Collects a fully qualified type reference if the givenTokenTypes.DOTnode represents one.private voidprocessIdent(DetailAST ast) Records a reference made through a simple name.private voidprocessImport(DetailAST ast) Records an import by its simple name so that later references can be resolved.private voidprocessPackage(DetailAST ast) Records the package the file belongs to.private booleanresolvesToQualifiedReference(String simpleName) Checks whether any fully qualified reference with the given simple name resolves to the same type as an unqualified reference would.private booleanresolvesUnqualified(String fullName) Determines whether a reference by simple name (without import or local declaration) would resolve to the type denoted by the given fully qualified name.private StringresolveViaOnDemandImport(String simpleName) Resolves a simple name against the file's on-demand imports, returning the fully qualified name of the class it resolves to, if any.voidvisitToken(DetailAST ast) Called to process a token.Methods inherited from class com.puppycrawl.tools.checkstyle.api.AbstractCheck
clearViolations, destroy, getFileContents, getFilePath, getLine, getLineCodePoints, getLines, getTabWidth, getTokenNames, getViolations, init, isCommentNodesRequired, leaveToken, log, log, log, setFileContents, setTabWidth, setTokensMethods inherited from class com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter
finishLocalSetup, getCustomMessages, getId, getMessageBundle, getSeverity, getSeverityLevel, setId, setSeverityMethods inherited from class com.puppycrawl.tools.checkstyle.AbstractAutomaticBean
configure, contextualize, getConfiguration, setupChild
-
Field Details
-
MSG_KEY
A key is pointing to the warning message text in "messages.properties" file.- See Also:
-
ARRAY_MARKERS
Array declarator markers that may trail a type name.- See Also:
-
DECLARED_MARKER
Marker used to represent a locally declared type in the identity set.- See Also:
-
UNQUALIFIED_MARKER
Marker used to represent an unqualified type reference in the identity set.- See Also:
-
JAVA_LANG_PACKAGE
Thejava.langpackage, types of which never need to be qualified.- See Also:
-
ON_DEMAND_IMPORT_SUFFIX
Suffix identifying an on-demand (wildcard) import, such asjava.util.*.- See Also:
-
DOT
Separator used between components of a fully qualified name.- See Also:
-
TYPE_CONTEXT_PARENTS
Tokens whose direct child is a type reference. ATokenTypes.DOTorTokenTypes.IDENTis considered to be in type context when its parent is one of these tokens. -
TYPE_DECLARATION_PARENTS
Tokens that declare a type. AnTokenTypes.IDENTwhose parent is one of these is the name of a type declared in the file. -
importedTypes
Maps the simple name of each single-type import to its fully qualified name. -
declaredTypes
Simple names of the types declared in the file. -
simpleReferences
Simple names of the types referenced without qualification in the file. -
qualifiedReferences
Fully qualified type references collected while traversing the file. -
onDemandImportPackages
Packages imported on-demand (wildcard), e.g.java.utilforimport java.util.*;. -
packageName
The package the file belongs to, ornullfor the default package.
-
-
Constructor Details
-
UnnecessaryFullyQualifiedTypeCheck
public UnnecessaryFullyQualifiedTypeCheck()Creates newUnnecessaryFullyQualifiedTypeCheckinstance.
-
-
Method Details
-
getDefaultTokens
Description copied from class:AbstractCheckReturns the default token a check is interested in. Only used if the configuration for a check does not define the tokens.- Specified by:
getDefaultTokensin classAbstractCheck- Returns:
- the default tokens
- See Also:
-
getAcceptableTokens
Description copied from class:AbstractCheckThe configurable token set. Used to protect Checks against malicious users who specify an unacceptable token set in the configuration file. The default implementation returns the check's default tokens.- Specified by:
getAcceptableTokensin classAbstractCheck- Returns:
- the token set this check is designed for.
- See Also:
-
getRequiredTokens
Description copied from class:AbstractCheckThe tokens that this check must be registered for.- Specified by:
getRequiredTokensin classAbstractCheck- Returns:
- the token set this must be registered for.
- See Also:
-
beginTree
Description copied from class:AbstractCheckCalled before the starting to process a tree. Ideal place to initialize information that is to be collected whilst processing a tree.- Overrides:
beginTreein classAbstractCheck- Parameters:
rootAST- the root of the tree
-
visitToken
Description copied from class:AbstractCheckCalled to process a token.- Overrides:
visitTokenin classAbstractCheck- Parameters:
ast- the token to process
-
finishTree
Description copied from class:AbstractCheckCalled after finished processing a tree. Ideal place to report on information collected whilst processing a tree.- Overrides:
finishTreein classAbstractCheck- Parameters:
rootAST- the root of the tree
-
processPackage
Records the package the file belongs to.- Parameters:
ast- theTokenTypes.PACKAGE_DEFnode
-
processImport
Records an import by its simple name so that later references can be resolved. On-demand (wildcard) imports do not have a single simple name, so the imported package is recorded separately instead.- Parameters:
ast- theTokenTypes.IMPORTnode
-
processDot
Collects a fully qualified type reference if the givenTokenTypes.DOTnode represents one.- Parameters:
ast- theTokenTypes#DOTnode
-
buildFullName
Reconstructs the fully qualified name for aTokenTypes#DOTnode, handling the extra child produced by an embedded type-use annotation.- Parameters:
ast- theTokenTypes#DOTnode- Returns:
- the fully qualified name the node represents
-
processIdent
Records a reference made through a simple name. The name is either an unqualified type reference or the name of a type declared in the file.- Parameters:
ast- theTokenTypes.IDENTnode
-
isUnnecessary
Determines whether a type reference with the given simple name is unnecessary. It is unnecessary when this fully qualified reference is the only type with that simple name used in the file, so it could be imported and referenced by its simple name without introducing ambiguity.- Parameters:
simpleName- the simple name of the type- Returns:
trueif the fully qualified reference is unnecessary
-
collectIdentities
Collects every distinct identity claiming the given simple name in the file: a direct import, each fully qualified reference sharing that simple name, a locally declared type, an unqualified reference resolving elsewhere, and a type reachable via an on-demand import. A simple name is unambiguous, and therefore its fully qualified reference unnecessary, exactly when this set has a single member.- Parameters:
simpleName- the simple name to collect identities for- Returns:
- the set of distinct identities claiming this simple name
-
addQualifiedReferenceIdentities
Adds an identity for each fully qualified reference sharing the given simple name.- Parameters:
simpleName- the simple name to match references againstidentities- the identity set to add to
-
resolvesToQualifiedReference
Checks whether any fully qualified reference with the given simple name resolves to the same type as an unqualified reference would.- Parameters:
simpleName- the simple name to check- Returns:
trueif an unqualified reference resolves to a matching qualified type
-
addImplicitIdentities
private void addImplicitIdentities(String simpleName, boolean unqualifiedResolvedToReference, Set<String> identities) Adds identities that are not established by an explicit import: an unqualified reference resolving to a same-package orjava.langtype, and a type reachable via an on-demand import. Only relevant when no direct import of this simple name exists, since a direct import always takes priority over an on-demand import.- Parameters:
simpleName- the simple name to checkunqualifiedResolvedToReference- whether a same-simple-name qualified reference already resolves to what an unqualified use would meanidentities- the identity set to add to
-
resolvesUnqualified
Determines whether a reference by simple name (without import or local declaration) would resolve to the type denoted by the given fully qualified name. This is the case when that name belongs to thejava.langpackage or to the package the file itself belongs to.- Parameters:
fullName- a fully qualified type name- Returns:
trueif an unqualified reference would resolve to it
-
resolveViaOnDemandImport
Resolves a simple name against the file's on-demand imports, returning the fully qualified name of the class it resolves to, if any. Resolution is attempted only against classes reachable on this check's own class loader, so it is reliable for JDK packages but cannot detect collisions caused by third-party or project-local on-demand imports.- Parameters:
simpleName- the simple name to look for- Returns:
- the fully qualified name the simple name resolves to via an
on-demand import, or
nullif none of the on-demand imported packages contain a class of that name
-
isInTypeContext
Checks whether the given node is a direct child of a type context token.- Parameters:
ast- the node to check- Returns:
trueif the node is in type context
-
isFullyQualified
Determines whether the given qualified name is a package qualified (fully qualified) type reference, as opposed to a reference to a nested type. The check relies on the convention that package names start with a lowercase letter, so the name is treated as fully qualified when the identifier preceding the simple name starts with a lowercase letter.- Parameters:
name- a qualified name containing at least one dot, as produced from aTokenTypes.DOTnode- Returns:
trueif the name is a fully qualified type reference
-
extractSimpleName
Extracts the simple name from a qualified name.- Parameters:
name- a qualified name- Returns:
- the part of the name after the last dot
-